
热爱编程,忠于开源的小码农
我的博客即将入驻“云栖社区”,诚邀技术同仁一同入驻。
<!DOCTYPE html> <html> <style> #biao1{ display: none !important; } </style> <div cols="20" id="biao1" >444444564564</div> <script type="text/javascript"> function copyUrl2() { var Url2=document.getElementById("biao1").innerText; var oInput = document.createElement('input'); oInput.value = Url2; document.body.appendChild(oInput); oInput.select(); // 选择对象 document.execCommand("Copy"); // 执行浏览器复制命令 oInput.className = 'oInput'; oInput.style.display='none'; alert('复制成功'); window.location.href="weixin://";//打开微信 } </script> <input type="button" onClick="copyUrl2()" value="点击复制代码" /> </html>
top命令(类似Windows下任务管理器,能够实时动态地监控并显示系统中各个进程的资源占用状况,是 Linux下常用的性能监控和分析工具。) top命令.png 详解: 来源见水印 命令详解 使用权限:所有使用者 使用方式:top [-] [d delay] [q] [c] [S] [s] [i] [n] [b] 说明:实时显示 process 的动态 参数: d : 改变显示的更新速度,或是在交谈式指令列( interactive command)按 s q : 没有任何延迟的显示速度,如果使用者是有 superuser 的权限,则 top 将会以最高的优先序执行 c : 切换显示模式,共有两种模式,一是只显示执行档的名称,另一种是显示完整的路径与名称S : 累积模式,会将己完成或消失的子行程 ( dead child process ) 的 CPU time 累积起来 s : 安全模式,将交谈式指令取消, 避免潜在的危机 i : 不显示任何闲置 (idle) 或无用 (zombie) 的行程 n : 更新的次数,完成后将会退出 top b : 批次档模式,搭配 "n" 参数一起使用,可以用来将 top 的结果输出到档案内 范例: 显示更新十次后退出 ; top -n 10 使用者将不能利用交谈式指令来对行程下命令 : top -s 将更新显示二次的结果输入到名称为 top.log 的档案里 : top -n 2 -b < top.log 运行top命令之后,如果想退出该命令,键入q即可或按ctrl c htop 命令(交互式命令) 优点 1、直接支持鼠标点击操作( 就问你6不6!) 2、画面可以水平垂直滚动,更像一个窗口 3、可以跟踪进程,显示进程打开的文件 4、支持进程的树状图显示 5、支持按照名称查找进程 我们接下来再来看一些图形化的操作: 进程树状图 image 鼠标点击各种指标来排序 image 跟踪进程功能 image image iotop 命令(是用来监控硬盘 IO的使用情况,UI 界面和 top类似,其中包括 PID、用户、I/O、进程 等相关信息。) Linux 下系统自带的IO统计工具如 iostat,nmon等大多数是只能统计到 per设备的读写情况,如果你想知道每个进程是如何使用 IO的就比较麻烦,使用 iotop命令可以很方便的查看。 image iftop 命令(iftop 是Linux系统的流量和带宽监控工具,可用于查看实时的网络流量、监控TCP/IP连接等,也是非常有用的!) 我们来做一下实验,命令执行后效果如下: image image iftop 命令常用的参数如下,这里做个小规模总结: -i 设定监测的网卡,如: # iftop -i eth1 -B 以bytes为单位显示流量 (默认是bits),如: # iftop -B -n 使 host信息默认直接都显示 IP,如: # iftop -n -N 使端口信息默认直接都显示端口号,如: # iftop -N -F 显示特定网段的进出流量,如 # iftop -F 10.10.1.0/24 或 # iftop -F 10.10.1.0/255.255.255.0 -h(display this message),帮助,显示参数信息 -p 使用这个参数后,中间的列表显示的本地主机信息,出现了本机以外的IP信息; -b 使流量图形条默认就显示; 再来总结一下,进入 iftop 视图画面后的一些操作命令 (注意大小写): 按 h切换是否显示帮助; 按 n切换显示本机的IP或主机名; 按 s切换是否显示本机的host信息; 按 d切换是否显示远端目标主机的host信息; 按 t切换显示格式为2行/1行/只显示发送流量/只显示接收流量; 按 N切换显示端口号或端口服务名称; 按 S切换是否显示本机的端口信息; 按 D切换是否显示远端目标主机的端口信息; 按 p切换是否显示端口信息; 按 P切换暂停/继续显示; 按 b切换是否显示平均流量图形条; 按 T切换是否显示每个连接的总流量; 按 l打开屏幕过滤功能,输入要过滤的字符,比如ip,按回车后,屏幕就只显示这个IP相关的流量信息; 按 L切换显示画面上边的刻度;刻度不同,流量图形条会有变化; 按 j或按 k可以向上或向下滚动屏幕显示的连接记录; 按 1或 2或 3可以根据右侧显示的三列流量数据进行排序; 按 <根据左边的本机名或 IP排序; 按 >根据远端目标主机的主机名或 IP排序; 按 o切换是否固定只显示当前的连接; 来源:CodeSheep
iptables -I INPUT -s 124.115.0.199 -j DROP # 是屏蔽124.115.0.199这个IP iptables -I INPUT -s 61.37.80.0/24 -j DROP # 是屏蔽61.37.80.*这段IP 意思就是61.37.80开头的IP iptables -I INPUT -s 124.115.0.0/16 -j DROP # 是屏蔽124.115.*.*这段IP 就是124.115开头的IP iptables -I INPUT -s 124.0.0.0/8 -j DROP # 是屏蔽124.*.*.*这段IP 意思就是124开头的IP 屏蔽是 -I 解封就是 -D 如果是只允许某个IP访问: 关闭防火墙的情况下,只允许几个特定IP 通过ssh服务远程登录到linux操作系统中: // 开启只允许几个IPssh到某个linux操作系统中vi /etc/hosts.allow sshd: 192.168.0.180:allow vi /etc/hosts.deny sshd:ALL service sshd restart 然后:wq保存就可以了
原因是时区没有设置 打开php.ini 位置在(/usr/local/php/etc/) date.timezone = Asia/Shanghai image.png
$con = mysql_connect("127.0.0.1","账号","密码"); if(!$con){ die('Could not connect:'.mysql_error()); } mysql_select_db("数据库名",$con); //操作数据库增删改查 . . . mysql_close($con);
先停掉mysql [root@instance-q6fz45kc etc]# service mysqld stop 编辑my.cnf文件,跳过验证,实现无密码登录 vim /etc/my.cnf 在my.cnf文件末尾加:skip-grant-tables后保存退出 然后启动mysql [root@instance-q6fz45kc etc]# service mysqld start 进入mysql [root@instance-q6fz45kc etc]# mysql 使用user库 mysql> use mysql 修改密码 mysql> update user set authentication_string=password('123456') where user="root"; 退出mysql exit 停掉mysql [root@instance-q6fz45kc etc]# service mysqld stop 打开my.cnf 去掉那会加的那段代码 重启mysql [root@instance-q6fz45kc etc]# service mysqld start 重新连接 [root@instance-q6fz45kc etc]# mysql -u root -p 输入密码连接成功! image.png
背景交代 折扣价格设置的是负数,框架用的TP5。 活动规则:当活动开始时候销售价格加上折扣价格(相当于减折扣价格)就是活动价格,当活动结束时候,减去折扣价格(负负得正)就恢复原价。这是才开始的预想。折扣价格已经设置成负的了。 大坑出现 当活动开始时候,加上负数,相当于减去折扣价格,实现优惠。这步骤没有问题。但是当活动结束时候,减负数就出现问题了,截图如下: image.png 水平不高,百度翻译一下: image.png 语法错误???? image.png 没毛病啊!!!纠结一上午,然后发现加法没事,就减法不行。 解决 abs()函数了解一下! 解决的办法就是:既然不让减负数,那老子不减了,取个绝对值,老子做加法还不行吗!!! image.png 老子惹不起还躲不起么。。。。
public function service() { $list['ip'] = $_SERVER["REMOTE_ADDR"]; $list['service'] = $this->get_os(); $list['broswer'] = $this->get_broswer(); $list['where'] = $this->position($list['ip']); dump($list);die; } /** * 获取客户端操作系统信息包括win10 * @param null * @author Jea杨 * @return string */ function get_os(){ $agent = $_SERVER['HTTP_USER_AGENT']; $os = false; if (preg_match('/win/i', $agent) && strpos($agent, '95')) { $os = 'Windows 95'; } else if (preg_match('/win 9x/i', $agent) && strpos($agent, '4.90')) { $os = 'Windows ME'; } else if (preg_match('/win/i', $agent) && preg_match('/98/i', $agent)) { $os = 'Windows 98'; } else if (preg_match('/win/i', $agent) && preg_match('/nt 6.0/i', $agent)) { $os = 'Windows Vista'; } else if (preg_match('/win/i', $agent) && preg_match('/nt 6.1/i', $agent)) { $os = 'Windows 7'; } else if (preg_match('/win/i', $agent) && preg_match('/nt 6.2/i', $agent)) { $os = 'Windows 8'; }else if(preg_match('/win/i', $agent) && preg_match('/nt 10.0/i', $agent)) { $os = 'Windows 10';#添加win10判断 }else if (preg_match('/win/i', $agent) && preg_match('/nt 5.1/i', $agent)) { $os = 'Windows XP'; } else if (preg_match('/win/i', $agent) && preg_match('/nt 5/i', $agent)) { $os = 'Windows 2000'; } else if (preg_match('/win/i', $agent) && preg_match('/nt/i', $agent)) { $os = 'Windows NT'; } else if (preg_match('/win/i', $agent) && preg_match('/32/i', $agent)) { $os = 'Windows 32'; } else if (preg_match('/linux/i', $agent)) { $os = 'Linux'; } else if (preg_match('/unix/i', $agent)) { $os = 'Unix'; } else if (preg_match('/sun/i', $agent) && preg_match('/os/i', $agent)) { $os = 'SunOS'; } else if (preg_match('/ibm/i', $agent) && preg_match('/os/i', $agent)) { $os = 'IBM OS/2'; } else if (preg_match('/Mac/i', $agent) && preg_match('/PC/i', $agent)) { $os = 'Macintosh'; } else if (preg_match('/PowerPC/i', $agent)) { $os = 'PowerPC'; } else if (preg_match('/AIX/i', $agent)) { $os = 'AIX'; } else if (preg_match('/HPUX/i', $agent)) { $os = 'HPUX'; } else if (preg_match('/NetBSD/i', $agent)) { $os = 'NetBSD'; } else if (preg_match('/BSD/i', $agent)) { $os = 'BSD'; } else if (preg_match('/OSF1/i', $agent)) { $os = 'OSF1'; } else if (preg_match('/IRIX/i', $agent)) { $os = 'IRIX'; } else if (preg_match('/FreeBSD/i', $agent)) { $os = 'FreeBSD'; } else if (preg_match('/teleport/i', $agent)) { $os = 'teleport'; } else if (preg_match('/flashget/i', $agent)) { $os = 'flashget'; } else if (preg_match('/webzip/i', $agent)) { $os = 'webzip'; } else if (preg_match('/offline/i', $agent)) { $os = 'offline'; } else { $os = '未知操作系统'; } return $os; } /** * 获取客户端浏览器信息 添加win10 edge浏览器判断 * @param null * @author Jea杨 * @return string */ function get_broswer(){ $sys = $_SERVER['HTTP_USER_AGENT']; //获取用户代理字符串 if (stripos($sys, "Firefox/") > 0) { preg_match("/Firefox\/([^;)]+)+/i", $sys, $b); $exp[0] = "Firefox"; $exp[1] = $b[1]; //获取火狐浏览器的版本号 } elseif (stripos($sys, "Maxthon") > 0) { preg_match("/Maxthon\/([\d\.]+)/", $sys, $aoyou); $exp[0] = "傲游"; $exp[1] = $aoyou[1]; } elseif (stripos($sys, "MSIE") > 0) { preg_match("/MSIE\s+([^;)]+)+/i", $sys, $ie); $exp[0] = "IE"; $exp[1] = $ie[1]; //获取IE的版本号 } elseif (stripos($sys, "OPR") > 0) { preg_match("/OPR\/([\d\.]+)/", $sys, $opera); $exp[0] = "Opera"; $exp[1] = $opera[1]; } elseif(stripos($sys, "Edge") > 0) { //win10 Edge浏览器 添加了chrome内核标记 在判断Chrome之前匹配 preg_match("/Edge\/([\d\.]+)/", $sys, $Edge); $exp[0] = "Edge"; $exp[1] = $Edge[1]; } elseif (stripos($sys, "Chrome") > 0) { preg_match("/Chrome\/([\d\.]+)/", $sys, $google); $exp[0] = "Chrome"; $exp[1] = $google[1]; //获取google chrome的版本号 } elseif(stripos($sys,'rv:')>0 && stripos($sys,'Gecko')>0){ preg_match("/rv:([\d\.]+)/", $sys, $IE); $exp[0] = "IE"; $exp[1] = $IE[1]; }else { $exp[0] = "未知浏览器"; $exp[1] = ""; } return $exp[0].'('.$exp[1].')'; } function get_position($ip){ if(empty($ip)){ return '缺少用户ip'; } $url = 'http://ip.taobao.com/service/getIpInfo.php?ip='.$ip; $ipContent = file_get_contents($url); $ipContent = json_decode($ipContent,true); $list = $ipContent['data']['country'].$ipContent['data']['region'].$ipContent['data']['city'].$ipContent['data']['isp']; return $list; }
安装: yum install subversion 创建svn目录 mkdir /home/svn cd /home/svn mkdir test svnadmin create test 以上指令就是创建了一个test文件夹,并且使用它作为仓库 修改svn配置文件(设定用户和用户权限)修改的文件注意等号两边是否有空格 修改第一个文件 cd test/conf/ vim svnserve.conf 红框前面的#号去掉,第一个改为none.png 修改第二个文件 增加一个用户.png 修改第三个文件 赋予这个用户可读可写的权限.png 创建钩子(要想实现本地修改svn提交,线上项目也改变.就是接下来的步骤了) 创建脚本 就是要创建这个文件.png vi ../hooks/post-commit #!/bin/sh #修改字符编码 export LANG=en_US.UTF-8 #svn编码是UTF-8,这个主要是防止乱码 REPOS="$1" REV="$2" SVN="/usr/bin/svn" WEB="/var/www/web/" #站点目录 #update the code from the SVN $SVN update $WEB --username=zheng --password=zheng123 --non-interactive --no-auth-cache #设置登陆账号密码并不缓存 赋予脚本权限 [root@instance-q6fz45kc hooks]# chmod 777 post-commit 重启svn killall svnserve svnserve -d -r /home/svn 进入存放代码目录,也就是线上项目的目录 cd /var/www/web 检出代码 [root@instance-q6fz45kc web]# svn checkout svn://180.76.103.58/test ./ 注意上面的主机地址和命令最后面的./ ,最后面的 ./ 表示把代码直接放到当前目录,不然他会自己创建一个test的目录,把代码放进去的 然后按照提示,yes 输入服务器密码 输入你的svn用户名(我的是zheng) 输入你的svn密码(我的是zheng123) 接下来就是本地使用了 创建index.html.png 上传成功.png 搞定.png
使用php-fpm解析PHP,"No input file specified","File not found"是常见错误,原因是php-fpm进程找不到SCRIPT_FILENAME配置的要执行的.php文件,php-fpm返回给nginx的默认404错误提示。 出现这类错误,十个有九个是后端fastcgi进程收到错误路径(SCRIPT_FILENAME),而后端fastcgi收到错误路径的原因大都是配置错误。 可以参考我的nginx.conf的配置: #user nobody; worker_processes 1; #error_log logs/error.log; #error_log logs/error.log notice; #error_log logs/error.log info; #pid logs/nginx.pid; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; #log_format main '$remote_addr - $remote_user [$time_local] "$request" ' # '$status $body_bytes_sent "$http_referer" ' # '"$http_user_agent" "$http_x_forwarded_for"'; #access_log logs/access.log main; sendfile on; #tcp_nopush on; #keepalive_timeout 0; keepalive_timeout 65; #gzip on; server { listen 80; server_name qanme.thenoob.top; #charset koi8-r; #access_log logs/host.access.log main; #这里配置存放网站代码的路径 location / { root /var/www/web; index index.html index.htm index.php; } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } # proxy the PHP scripts to Apache listening on 127.0.0.1:80 # #location ~ \.php$ { # proxy_pass http://127.0.0.1; #} # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 # location ~ \.php$ { root html; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; #输入网址是下载文件多半是下面一行的错误 fastcgi_param SCRIPT_FILENAME /var/www/web$fastcgi_script_name; include fastcgi_params; } # deny access to .htaccess files, if Apache's document root # concurs with nginx's one # #location ~ /\.ht { # deny all; #} } # another virtual host using mix of IP-, name-, and port-based configuration # #server { # listen 8000; # listen somename:8080; # server_name somename alias another.alias; # location / { # root html; # index index.html index.htm; # } #} # HTTPS server # #server { # listen 443 ssl; # server_name localhost; # ssl_certificate cert.pem; # ssl_certificate_key cert.key; # ssl_session_cache shared:SSL:1m; # ssl_session_timeout 5m; # ssl_ciphers HIGH:!aNULL:!MD5; # ssl_prefer_server_ciphers on; # location / { # root html; # index index.html index.htm; # } #} }
遇到这种问题,通常是由于fastcgi_script_name访问脚本路径不正确引起的。 image.png 问题就在这里,把原来的fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 改为存放代码的路径
下载插件包 yum -y install gcc gcc-c++ libxml2 libxml2-devel bzip2 bzip2-devel libmcrypt libmcrypt-devel openssl openssl-devel libcurl-devel libjpeg-devel libpng-devel freetype-devel readline readline-devel libxslt-devel perl perl-devel psmisc.x86_64 recode recode-devel libtidy libtidy-devel epel-release libmcrypt-devel 下载 cd /usr/local/src/ wget http://cn2.php.net/distributions/php-5.6.32.tar.gz 解压 tar zxvf php-5.6.32.tar.gz 预编译 cd php-5.6.32 创建php-fpm用户,并禁止登录; useradd -s /sbin/nologin php-fpm ./configure --prefix=/usr/local/php --sysconfdir=/usr/local/php/etc --with-config-file-path=/usr/local/php/etc/ --with-fpm-user=php-fpm --with-fpm-group=php-fpm --enable-fpm --with-mysql=mysqlnd --with-mysqli=mysqlnd --with-pdo-mysql=mysqlnd --with-mhash --with-openssl --with-zlib --with-bz2 --with-curl --with-libxml-dir --with-gd --with-jpeg-dir --with-png-dir --with-zlib --enable-mbstring --with-mcrypt --enable-sockets --with-iconv-dir --enable-zip --with-pcre-dir --with-pear --enable-session --enable-gd-native-ttf --enable-xml --with-freetype-dir --enable-gd-jis-conv --enable-inline-optimization --enable-shared --enable-bcmath --enable-sysvmsg --enable-sysvsem --enable-sysvshm --enable-mbregex --enable-pcntl --with-xmlrpc --with-gettext --enable-exif --with-readline --enable-ftp --enable-redis 提示错误mcrypt.h没有找到,安装libmcrypt-devel包,默认的yum源,没有这个包,需要安装epel扩展源后,才可以安装。 [root@localhost php-5.6.32]# yum install -y epel-release [root@localhost php-5.6.32]# yum install -y libmcrypt [root@localhost php-5.6.32]# yum install -y libmcrypt-devel 再次执行./configure,没有错误提示,出现Thank you for using PHP,配置OK。 image.png 检查是否安装正确 make && make install echo $? 如果出现0 就说明正确了. 配置文件 需要将当前目录下的php.ini文件拷贝到 php的安装目录etc下 cp php.ini-production /usr/local/php/etc/php.ini php.ini 文件是在包目录下的 php.ini-development(开发), php.ini-production(生产) 拷贝php启动脚本,php-fpm配置文件,更改php-fpm权限为755;添加php-fpm开机启动; [root@ php-5.6.32]# cp /usr/local/src/php-5.6.32/sapi/fpm/init.d.php-fpm /etc/init.d/php-fpm (启动脚本) [root@ php-5.6.32]# mv /usr/local/php/etc/php-fpm.conf.default /usr/local/php/etc/php-fpm.conf (就是去掉了末尾的.default ) [root@ php-5.6.32]# chmod 755 /etc/init.d/php-fpm [root@lphp-5.6.32]# chkconfig --add php-fpm [root@lphp-5.6.32]# service php-fpm start Starting php-fpm done [root@php-5.6.32]# chkconfig php-fpm on 将php的安装目录也加入到系统的环境变量 在最后一行加入 vim /etc/profile export PATH=/usr/local/php/bin:$PATH source /etc/profile //重新加载 [root@localhost ~]# php -v PHP 5.6.32 (cli) (built: Mar 12 2018 17:43:15) Copyright (c) 1997-2016 The PHP Group Zend Engine v2.6.0, Copyright (c) 1998-2016 Zend Technologies完成 接下来就是测试 vim /usr/local/nginx/conf/nginx.conf location / { root /www/test; index index.html index.htm index.php; try_files $uri $uri/ /index.php?$query_string; if (!-e $request_filename){ rewrite ^(.*)$ /index.php?s=$1 last; break; } } 将请求转给php的9000端口 确保nginx 和PHP都是运行的哈。 location ~ \.php$ { root /www/test; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } 我的是根目录下的www/ 写个index.php 里面加入phpinfo(); 看能否成功。 image.png
安装MySQL 切换目录 cd /usr/local/src/ 下载安装包 wget http://repo.mysql.com/mysql57-community-release-el7-8.noarch.rpm 执行 rpm -ivh mysql57-community-release-el7-8.noarch.rpm 安装 yum -y install mysql-server 重置密码 grep "password" /var/log/mysqld.log image.png mysql -u root -p 密码 进入 接下来重置密码:5.7.20 为了安全密码 必须包含 数字字母符号 alter user 'root'@'localhost' identified by '!!Admin123'; 最后记得刷新权限;flush privileges ; image.png
$where = array(); $where['discount_price'] = ['<',0]; $where['state'] = 1; $list = db('ns_goods')->where($where)->group('goods_id')->field('goods_id,discount_price')->select();;
安装nginx 确保没有安装扩展 yum install wget gcc gcc-c++ pcre-devel zlib-devel openssl openssl-devel 然后: cd /usr/local/src/ wget http://nginx.org/download/nginx-1.12.2.tar.gz 下载完成之后解压: tar zxvf nginx-1.12.2.tar.gz 预编译: [root@localhost nginx-1.12.2]# ./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-http_v2_module --with-http_stub_status_module --with-pcre --with-http_gzip_static_module --with-http_dav_module --with-http_addition_module --with-http_sub_module --with-http_flv_module --with-http_mp4_module 解释: --with-http_gzip_static_module :支持压缩 --with-http_stub_status_module :支持nginx状态查询 --with-http_ssl_module :支持https --with-pcre :为了支持rewrite重写功能,必须制定pcre --with-http_dav_module #启用支持(增加PUT,DELETE,MKCOL:创建集合,COPY和MOVE方法) --with-http_addition_module #启用支持(作为一个输出过滤器,支持不完全缓冲,分部分相应请求) --with-http_sub_module #启用支持(允许一些其他文本替换Nginx相应中的一些文本) --with-http_flv_module #启用支持(提供支持flv视频文件支持) --with-http_mp4_module #启用支持(提供支持mp4视频文件支持,提供伪流媒体服务端支持) 编译: make && make install 添加系统变量(方便启停服务) vim /etc/profile 第56行添加 export PATH=/usr/local/nginx/sbin:$PATH 然后重新启动 source /etc/profile 添加软连接 ln -s /usr/local/nginx/sbin/nginx /usr/local/sbin/ 服务器启动脚本: vim /etc/init.d/nginx 把下面内容放进去 #!/bin/bash # chkconfig: - 99 2 # description: Nginx Service Control Script PROG="/usr/local/nginx/sbin/nginx" PIDF="/usr/local/nginx/logs/nginx.pid" case "$1" in start) $PROG ;; stop) kill -3 $(cat $PIDF) ;; restart) $0 stop &> /dev/null if [ $? -ne 0 ] ; then continue ; fi $0 start ;; reload) kill -1 $(cat $PIDF) ;; *) echo "Userage: $0 { start | stop | restart | reload }" exit 1 esac exit 0 配置服务开机自动启动 [root@localhost ~]# chmod +x /etc/init.d/nginx [root@localhost ~]# chkconfig --add nginx [root@localhost ~]# chkconfig nginx on 配置完了可以用一下命令控制nginx状态: service nginx restart service nginx start service nginx stop 打开浏览器输入你的ip就可以看到welcome to nginx!
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>原生点击按钮加载更多(懒加载,每次加载N个)</title> <style> *{margin: 0;padding:0;list-style: none;} body{background: #333;font-size: 14px;font-family:"微软雅黑"} a{color: #333;text-decoration: none;} .hidden{ display: none;} .lanren{width: 800px;height: auto;margin:0 auto;overflow: hidden;text-align: left;background:#fff;padding:5px;} .lanren ul.list{overflow: hidden;} .lanren ul.list li{width: 150px;height: 150px;margin:5px;float: left;overflow: hidden;} .lanren ul.list li img{width: 100%;height: 100%;} .lanren ul.list p{text-align: center;padding: 10px;} .lanren .more{overflow: hidden;padding:10px;text-align: center;} .lanren .more a{display: block;width: 80px;padding:8px 0;color:#fff;margin:0 auto;background:#333;text-align:center;border-radius:3px;} .lanren .more a:hover{text-decoration: none;background: red;color: #fff;} </style> </head> <body> <div style="margin:auto;width:830px;"> <script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script> <!-- 详情页banner --> <ins class="adsbygoogle" style="display:inline-block;width:830px;height:120px" data-ad-client="ca-pub-4078329886972765" data-ad-slot="4189420132"></ins> <script> (adsbygoogle = window.adsbygoogle || []).push({}); </script> </div> <!--代码部分begin--> <div class="lanren"> <div class="hidden"> <li><img src="images/1px.gif" realSrc="images/lanren01.jpg" width="150" height="150" /></li> <li><img src="images/1px.gif" realSrc="images/lanren02.jpg" width="150" height="150" /></li> <li><img src="images/1px.gif" realSrc="images/lanren03.jpg" width="150" height="150" /></li> <li><img src="images/1px.gif" realSrc="images/lanren04.jpg" width="150" height="150" /></li> <li><img src="images/1px.gif" realSrc="images/lanren05.jpg" width="150" height="150" /></li> <li><img src="images/1px.gif" realSrc="images/lanren06.jpg" width="150" height="150" /></li> <li><img src="images/1px.gif" realSrc="images/lanren07.jpg" width="150" height="150" /></li> <li><img src="images/1px.gif" realSrc="images/lanren08.jpg" width="150" height="150" /></li> <li><img src="images/1px.gif" realSrc="images/lanren09.jpg" width="150" height="150" /></li> <li><img src="images/1px.gif" realSrc="images/lanren10.jpg" width="150" height="150" /></li> <li><img src="images/1px.gif" realSrc="images/lanren11.jpg" width="150" height="150" /></li> <li><img src="images/1px.gif" realSrc="images/lanren12.jpg" width="150" height="150" /></li> <li><img src="images/1px.gif" realSrc="images/lanren13.jpg" width="150" height="150" /></li> <li><img src="images/1px.gif" realSrc="images/lanren14.jpg" width="150" height="150" /></li> <li><img src="images/1px.gif" realSrc="images/lanren15.jpg" width="150" height="150" /></li> <li><img src="images/1px.gif" realSrc="images/lanren16.jpg" width="150" height="150" /></li> <li><img src="images/1px.gif" realSrc="images/lanren17.jpg" width="150" height="150" /></li> <li><img src="images/1px.gif" realSrc="images/lanren18.jpg" width="150" height="150" /></li> <li><img src="images/1px.gif" realSrc="images/lanren19.jpg" width="150" height="150" /></li> <li><img src="images/1px.gif" realSrc="images/lanren20.jpg" width="150" height="150" /></li> <li><img src="images/1px.gif" realSrc="images/lanren21.jpg" width="150" height="150" /></li> <li><img src="images/1px.gif" realSrc="images/lanren22.jpg" width="150" height="150" /></li> <li><img src="images/1px.gif" realSrc="images/lanren23.jpg" width="150" height="150" /></li> <li><img src="images/1px.gif" realSrc="images/lanren24.jpg" width="150" height="150" /></li> <li><img src="images/1px.gif" realSrc="images/lanren25.jpg" width="150" height="150" /></li> <li><img src="images/1px.gif" realSrc="images/lanren26.jpg" width="150" height="150" /></li> <li><img src="images/1px.gif" realSrc="images/lanren27.jpg" width="150" height="150" /></li> <li><img src="images/1px.gif" realSrc="images/lanren28.jpg" width="150" height="150" /></li> <li><img src="images/1px.gif" realSrc="images/lanren29.jpg" width="150" height="150" /></li> <li><img src="images/1px.gif" realSrc="images/lanren30.jpg" width="150" height="150" /></li> <li><img src="images/1px.gif" realSrc="images/lanren31.jpg" width="150" height="150" /></li> <li><img src="images/1px.gif" realSrc="images/lanren32.jpg" width="150" height="150" /></li> <li><img src="images/1px.gif" realSrc="images/lanren33.jpg" width="150" height="150" /></li> <li><img src="images/1px.gif" realSrc="images/lanren34.jpg" width="150" height="150" /></li> <li><img src="images/1px.gif" realSrc="images/lanren35.jpg" width="150" height="150" /></li> <li><img src="images/1px.gif" realSrc="images/lanren36.jpg" width="150" height="150" /></li> <li><img src="images/1px.gif" realSrc="images/lanren37.jpg" width="150" height="150" /></li> <li><img src="images/1px.gif" realSrc="images/lanren38.jpg" width="150" height="150" /></li> <li><img src="images/1px.gif" realSrc="images/lanren39.jpg" width="150" height="150" /></li> <li><img src="images/1px.gif" realSrc="images/lanren40.jpg" width="150" height="150" /></li> <li><img src="images/1px.gif" realSrc="images/lanren41.jpg" width="150" height="150" /></li> <li><img src="images/1px.gif" realSrc="images/lanren42.jpg" width="150" height="150" /></li> <li><img src="images/1px.gif" realSrc="images/lanren43.jpg" width="150" height="150" /></li> <li><img src="images/1px.gif" realSrc="images/lanren44.jpg" width="150" height="150" /></li> <li><img src="images/1px.gif" realSrc="images/lanren45.jpg" width="150" height="150" /></li> </div> <ul class="list">数据加载中,请稍后...</ul> <div class="more"><a href="javascript:;" onClick="javascript:loadMore();">加载更多</a></div> </div> <script src="http://www.lanrenzhijia.com/ajaxjs/jquery.min.js"></script> <script> var _default = 10; //默认显示图片个数 var _loading = 5; //每次点击按钮后加载的个数 var _content = [];//用来存储li循环内容 function init(){ var lis = $(".lanren .hidden li"); $(".lanren ul.list").html(""); for(var n=0;n<_default;n++){ lis.eq(n).appendTo(".lanren ul.list"); } $(".lanren ul.list img").each(function(){ $(this).attr('src',$(this).attr('realSrc')); }) for(var i=_default;i<lis.length;i++){ _content.push(lis.eq(i)); } $(".lanren .hidden").html(""); } init(); function loadMore(){ var k =0,t,i; var mLis = $(".lanren ul.list li").length; for(i= mLis-_default;i<mLis-_loading;i++){ if(i == _content.length){ $('.lanren .more').html("<p>全部加载完毕...</p>"); break; } _content[i].appendTo(".lanren ul.list"); t = mLis + k; k++; $(".lanren ul.list img").eq(t).each(function(){ $(this).attr('src',$(this).attr('realSrc')); }); } } </script> <!--代码部分end--> </body> </html>
1、父标签 position属性为relative; 2、问题标签无position属性(不包括static); 3、问题标签含有浮动(float)属性。 这样也很好理解为什么parent设置了position和z-index之后insert的z-index就会失效的问题了,他的解决办法有是三个: 1、position:relative改为position:absolute; 2、浮动元素添加position属性(如relative,absolute等); 3、去除浮动。
在公共的common.php中 function subtext($text, $length) { if(mb_strlen($text, ‘utf8’) > $length) return mb_substr($text,0,$length,’utf8′).’ …’; return $text; } 在模版中调用则: {$tops.title | subtext=18}
<style> line-height: 30px; text-align: center; text-overflow:ellipsis;/*让超出的用...实现*/ white-space:nowrap;/*禁止换行*/ overflow:hidden;/*超出的隐藏*/ display: block; </style> 多行: <style> border:1px solid #ddd; width: 200px; word-break: break-all; text-overflow: ellipsis; display: -webkit-box; /** 将对象作为伸缩盒子模型显示 **/ -webkit-box-orient: vertical; /** 设置或检索伸缩盒对象的子元素的排列方式 **/ -webkit-line-clamp: 3; /** 显示的行数 **/ overflow: hidden; /** 隐藏超出的内容 **/ </style>
/ px转换rem var IntervalId = 0; window.onload = function() { IntervalId = self.setInterval("RemCount()", 100); }; function RemCount() { var ClientWidth = document.documentElement.clientWidth || document.body.clientWidth; if (ClientWidth < 10) { return; } var viewport = document.querySelector("meta[name=viewport]"); if (window.devicePixelRatio == 1) { viewport.setAttribute('content', 'width=device-width,initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no'); } if (window.devicePixelRatio == 2) { viewport.setAttribute('content', 'width=device-width,initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5, user-scalable=no'); } if (window.devicePixelRatio == 3) { viewport.setAttribute('content', 'width=device-width,initial-scale=0.3333333333333333, maximum-scale=0.3333333333333333, minimum-scale=0.3333333333333333, user-scalable=no'); } // 1rem = 10rem 默认最低比例为1:16,如果低于此比例会强制使用1:16,从而引起高度的巨大问题(自行测试) var ClientWidth = document.documentElement.clientWidth || document.body.clientWidth; if (ClientWidth > 0) { localStorage.ClientWidth = ClientWidth; } else { ClientWidth = localStorage.ClientWidth; } document.documentElement.style.fontSize = ClientWidth / 7.5 + 'px'; console.log("PHP页提示,宽度及rem比例:" + ClientWidth + " / " + (ClientWidth/7.5)); if (ClientWidth > 0) { window.clearInterval(IntervalId); } }
function _do_edit(id) { $.confirm({ boxWidth: '900px', title: '商品编辑', content: '<iframe src="/index.php?call=mall.spu_edit&id=' + id + '" frameborder="0" scrolling="no" id="spuform" name="spuform" style="width:95%;height:500px;"></iframe>', buttons: { close: {text: '关闭'}, exec: {text: '保存', btnClass: 'btn-blue', action: function () { window.frames["spuform"].document.forms["spuform"].submit();//跨域问题解决 location.reload(); }} }, onOpen: function () { } }); }
开篇我们附上最符合本吧主题的Windows 7微软原版无修改的系统镜像下载地址:****Windows 764位旗舰版 ed2k://|file|cn_windows_7_ultimate_with_sp1_x64_dvd_u_677408.iso|3420557312|B58548681854236C7939003B583A8078|/ Windows 732位旗舰版 ed2k://|file|cn_windows_7_ultimate_with_sp1_x86_dvd_u_677486.iso|2653276160|7503E4B9B8738DFCB95872445C72AEFB|/ 备注:您可以直接将上述地址复制到迅雷等下载工具中下载。我们不提倡使用第三方修改的系统(例如常见的雨林木风、深度、电脑公司等等),同时我们也会对发布各种Ghost版本系统或者含有流氓行为的类原版系统者进行严惩!如需下载其他更多系统请至贴吧右侧的实用信息上查看。我们并不是盲目的向您推荐所谓“官方”的东西,在下面的教程中您将看到我们也适时的给您提供了合理的选择。 安装前的准备工作****首先我们需要确定我们要安装的系统。以Windows 7为例,他分为32位与64位版本。如果您的内存超过4GB时,请务必安装64位版本,请不要使用32位版本进行“内存破解”,这将严重影响您机器的稳定性。如果您的内存刚好是4GB,那么无论哪个版本区别不大。但如果您刚准备从XP升级到Windows 7或内存不足4GB,那么这里我建议您选择32位版本。至于对基本版、家庭基础版、家庭高级版、专业版、企业版以及旗舰版的选择,您可以自行斟酌。但不论您选择何种版本,在兼容性、稳定性以及资源消耗上都没有区别。如果无从下手建议您直接选择旗舰版。选择好您需要的系统下载后,建议您继续做如下准备:****(一)适合您机器的驱动****为了使机器各硬件能够正常使用,您必须准备好对应您机器的驱动(同时也必须对应系统和位数)。如果没有驱动您可能会遇到显示器无法调节到最佳分辨率、无法玩游戏、无法上网、无法识别您的外设等情况。这些驱动您可以根据您的硬件自行搜索并下载,多数笔记本也会配有驱动光盘或者在品牌官网提供驱动下载。或者您也可以选择事先准备带有万能网卡驱动的“驱动精灵”、“驱动人生”等工具,只要保证网卡先正常工作,其余驱动可由工具帮您下载(但这是在您无法找到最合适您的驱动的时候才建议)。****(二)类运行时的安装包****您无需关心其具体如何工作,您需要知道的是没有了这些东西一些程序将无法正常工作。建议您至少安装如下两类:****Microsoft Visual C++ Redistributable Package <u>http://www.microsoft.com/zh-cn/search/DownloadResults.aspx?q=Microsoft+Visual+C%2b%2b+Redistributable+Package</u> 备注:2005、2008、2010、2012、2013等没有向下兼容的关系,64位系统建议您全部安装,32位系统安装带有“x86”的即可。 DirectX 最终用户运行时 <u>http://www.microsoft.com/zh-cn/download/details.aspx?id=35</u> 备注:此为联机安装程序,安装时需要联网,您也可以搜索其离线版本。 【醒目】<u>http://pan.baidu.com/s/1pJv01mF</u>,这里是onenote版本和pdf版本的教程和一些可能用到的资源合集,资源内容可能会不定时更新。onenote版本或PDF版本可以避免排版上造成的错误并包含一些不当之处的更正。 最基本的安装方法****适用范围:****在包括XP在内的32位系统下安装32位的Windows 7、Windows 8、Windows 8.1with update。****在64位系统下安装32位或64位的Windows 7、Windows 8、Windows 8.1 with update。 备注:我们默认认为XP系统为32位,不考虑极少数特例。我们的图片以XP下的操作为例,其他系统下大同小异不再截图说明。另外Windows 8.1不带update的版本已不建议您安装了。 当我们下载完成了系统文件,我们第一步要做的就是利用解压软件将其解压出来(注意是提取到某处,而不是直接打开它。如果您的的解压软件无法解压iso文件,请升级软件版本。同时我们也不提倡使用虚拟光驱来操作,更不要画蛇添足跑到第三方PE下操作。我们完全不需要第三方PE,请丢掉您的错误习惯。),解压后我们可以得到如图所示结构的一些文件(不同系统、不同位数文件会有所出入)。 image.png 点击setup(建议您操作前关闭安全防护软件),您将看到向导出现,下面我们直接用图片进行说明。 image.png 需再次等待一段时间 image.png 此处不管您做任何选择,对安装都几乎无影响。 image.png 请务必接受许可条款! image.png 通常这里我们不使用(更多时候是无法使用)“升级”。 image.png 来到选择分区的界面,此时您无法也无需格式化磁盘。 image.png 如果您安装到系统盘,弹出下面的提示请确定。 image.png 到这里就暂时没什么事了。 image.png 此为最基本安装方式,接下来请跳到后续操作部分。 从介质启动安装的方法 提示:如果您使用上面的方式已经顺利进行,请跳到后续操作部分,此为另一种方法。 适用范围: 与目标计算机现有操作系统无关,在主流Windows系统下完成介质的制作后可用于对任意现有系统(包括Linux、Dos)甚至无系统的主机进行安装。 如果您手头有空白光盘和刻录机,您可以将下载的ISO镜像刻录到光盘上完成介质的制作。如果没有,我们可以有U盘来取代光盘的作用。 制作启动U盘我们推荐您使用UltraISO这款软件来操作(付费软件,但可以试用,网上也有大量破解版,但建议您支持正版,其价格也非常低廉)。我们也不建议使用微软官方提供的制作工具,更不建议使用诸如“魔方”等第三方工具,实践证明UltraISO是最为可靠的。再次申明,强烈抵制诸如“老毛桃”、“大白菜”、“电脑店”、“U大师”等等这一类型的工具,任何推广都会受到一天到无期不等的封禁处罚。请广大吧友舍弃糟粕,回归科学! 安装UltraISO后使用该软件打开我们之前下载好的ISO镜像。(如果您在Win7或Win8下制作启动盘,建议您右击UltraISO使用管理员身份运行) image.png 我们大概可以看到类似下图的结构出现。 image.png 插入您的优盘,点击启动中的写入硬盘映像。 image.png 建议您以默认配置直接写入(注意:该操作会格式化您的优盘,请提前做好备份) image.png 等进度条走完,一个启动U盘就完成了,现在你可以拿到您需要安装系统的电脑上从U盘来启动。 现多数电脑都设有快捷启动菜单,在打开电源后快速按键盘即可进入菜单(不同机器快捷键有所不同,主要集中在F12、ESC等,请主动尝试或观察开机的提示),辨别出你的U盘名称选择从U盘启动。 如果遇到一些机型快捷启动菜单默认关闭的情况,那我们就要使用更加标准的进入BIOS(UEFI)修改第一启动项的方式(关于BIOS和UEFI的更多信息会在后文中提及,您可以暂将其理解为一个电脑自带的基本系统)。进入的快捷键一般集中在Del、F2、F9上。由于不同机器界面也不一致,我们仅仅示例性的提供截图说明。 如图所示的第三项为我们的U盘: image.png 在修改完配置后切记保存并退出,通常快捷键为F10. 启动时你大概会看到如下的界面 image.png 到这里我们就进入了官方的PE(预原装环境)中,首先选择语言相关设置 image.png 下面有两条路可选,安装系统选择现在安装,而修复计算机则是在系统故障时进行修复使用。 image.png 稍后几步与在正常系统下安装是一样的。略有不同的是现在我们可以使用驱动器选项对硬盘进行分区操作。后续步骤一致。 image.png 请按自己的需要来进行分区,亦可不操作直接下一步(请不用考虑4K对齐问题,使用原版PE分区本身就是对其的)。 当计算机第一次重启后请取出启动介质,以免循环安装。另外,如果是Win7,则原版PE不带有USB3.0驱动,若U盘插在USB3.0接口(蓝色)会导致提示驱动器错误,请使用2.0接口(黑色),Win8以上则无此问题。 接下来请跳到后续操作部分。 后续操作 不论前面您使用何种方式进行安装,最后的后续操作都是一致的。请从上述选择一种方式安装然后进行后续的操作过程。 如果一切顺利,经过若干次重启之后您将看到如下画面。首先,您可以自定义一个用户名称,推荐使用英文。 image.png 设置您的密码,可留空。 image.png 根据版本的不同,您可能会被要求输入密钥,此时可以直接点击跳过。 image.png 选择合适的时区 image.png 您可能还会看到下图,请根据实际情况选择,无法抉择请选公用网络。 image.png 全新安装好的系统桌面上将只有一个回收站,您可以按自己喜好设置(注意:Office与系统是独立销售的,如果需要请再安装,推荐使用Office 2010以上的版本)。如果您原来的系统未格式化,您现在可以通过磁盘清理来清理旧系统文件。 接下来我们要做的就是安装我们事先准备好的驱动或驱动工具以及各类运行时。由于过程过于简单,我们不截图说明。 关于系统激活问题我们不做讨论,请尽可能支持正版。如经济能力有限,请百度或谷歌搜索Windows loader等等。请不要受不法商人的迷惑。本吧不对您的盗版行为负责,也不会指责这种做法。但是请低调使用盗版,对于使用盗版还优越感十足者我们同样会给予一定惩罚。 补充说明 之后的内容希望您在具备一定基础后再进行阅读,我们恐怕难以对一些过于简单的细节一一讲解。 (一)上述第一种方法中仅依靠解压软件就完成了系统安装,但是缺点是无法在32位系统下安装64位系统。故而我们更加推荐第二种方案。但假设我们手头真的没有U盘,那么可以用手机卡配合读卡器代替。如果还没有,其实也可以直接利用硬盘自身来代替。那么方法无非是让硬盘上的引导直接指向PE,可根据如下两种情况操作(不借助更多第三方工具)。 1、当您当前系统为XP,要直接升级到64位Win7以上系统时,我们可以把镜像的内容解压到“系统盘”,然后打开隐藏文件的显示,删除或重命名系统盘中的ntldr文件,然后把bootmgr文件重命名为ntldr,重启计算机后与U盘启动安装过程无异。但是要注意千万不要格式化了原系统盘,否则我们的安装源文件也就没了。此法并不推荐使用,其存在一定风险。并且我们也没必要从XP就直接升级到64位版本的系统。 2、当您当前系统为32位的Win7以上系统时,可能由于后期添加了内存,我们需要把系统升级到64位时。我们把64位镜像解压到任意盘(这里假设为D盘)根目录。然后运行bcdedit命令添加一条PE的启动信息到当前配置文件。命令如下: bcdedit /create /d "Windows PE" /device 这会生成一个GUID,格式为{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx},根据此ID执行后续命令 bcdedit /set {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} ramdisksdidevicepartition=d: bcdedit /set {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} ramdisksdipath \boot\boot.sdi bcdedit /create /d "Windows PE" /application osloader 这会生成另一个GUID,格式为{yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy} ,根据此ID和上面的ID执行后续命令 bcdedit /set {yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy} deviceramdisk=[d:]\sources\boot.wim,{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} bcdedit /set {yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy} osdeviceramdisk=[d:]\sources\boot.wim,{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} bcdedit /set {yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy} path\windows\system32\boot\winload.exe bcdedit /set {yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy} systemroot\windows bcdedit /set {yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy} detecthal yes bcdedit /set {yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy} winpe yes bcdedit /set {yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy} nx optin bcdedit /displayorder {yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy}/addlast 重启后就可以看到PE的启动菜单,安装过程同上。(提示:您无需记忆这些命令,您可以将其保存到记事本,使用时将GUID批量替换再复制到命令行中执行) 上述两种方式安装完系统可能会在启动菜单上留下残留,您可以运行msconfig命令后找到并删除多余启动项目。 (二)经常有人因为买个一个预装Win8的笔记本不适应而要换成Win7(其实我们不建议大家换到Win7,一方面技术总是在发展的,一个界面的改变并不是什么大事,用用就习惯了。另一方面,降级之后不一定能够找到合适的驱动,硬件不能完美使用)。 那么如果您非要换到Win7,您只要注意两件事就可以了。 1、选择64位版本的Win7。因为预装Win8的本都是比较新的机型,一方面是64位更加能发挥性能,另一方面许多都是有64位驱动无32位驱动的。并且依旧可以使用UEFI,不必对磁盘进行重新划分。 2、关闭安全启动(Secure Boot)。只要在BIOS(UEFI)中关闭了这一项,那么降级到Win7就已经没有直接阻碍了。就算是用盗版要激活,选择与旗舰版功能一致的企业版即可。 image.png 当然,部分BIOS(UEFI)下您还必须做出类似下图的修改,具体要看每个人自己的设备问题了。 image.png 系统启动流程 为了进一步灵活的进行操作系统的安装,我建议您熟悉操作系统的启动流程。当然,这里我们暂只讨论Windows平台(Windows 8开始提供了ARM的支持,其在ARM架构上亦采用UEFI)。 现今的PC分为传统BIOS和UEFI两种启动方式。其中BIOS为旧技术,存在很大局限性,目前正处于从BIOS到UEFI的过渡阶段,因而多数采用UEFI的PC依然可以使用BIOS兼容模式(这里指PC的x86平台,在ARM平台上不作这种兼容,另外ARM上的Secure Boot是不可关闭的)。 BIOS下的启动过程: 加电自检->按顺序尝试启动项->主引导记录(mbr)->分区引导记录(pbr)->启动管理器(bootmgr)->配置文件(bcd)->winload.exe->ntoskrnl.exe->注册表 UEFI下的启动过程: 加电初始化->efi shell->启动管理器(*.efi)->配置文件(bcd)->winload.efi->ntoskrnl.exe->注册表 从流程上可以看出UEFI的启动步骤有所减少,另加上BIOS工作在16位实模式下,而UEFI则有32位和64位版本(现今常见的都是64位版本,32位未普及就已被抛弃),因此理论上的开机速度自然更快,这点在网络启动时差异非常明显(后续我们也将介绍这种方式)。当您的计算机支持UEFI并且您想使用64位系统时建议使用UEFI启动方式。 在UEFI方式下没有经过主引导记录和分区引导记录这两个环节而是直接转到UEFI可识别的分区下的启动管理器。通常我们需要一个FAT32格式的分区(NTFS是不被直接支持的),而启动管理器通常位于分区中的efi文件夹下的boot文件夹中并以efi结尾(您也可以在efi shell中修改路径,但部分主板并不直接提供efi shell)。实际我们前面通过工具来制作启动U盘就是修改了U盘上的主引导记录和分区引导记录并把镜像中的文件释放到了U盘。故而如果您想使用UEFI方式从U盘启动只需要保证U盘为FAT32格式并将系统镜像(64位)中的文件解压到U盘中而无需使用启动盘制作工具(Windows 8以上这样就可以了,但是Windows 7原版镜像中在efi目录下没有boot,因此您需要自行建立此目录并从系统目录或其他手段获取所需的bootx64.efi文件,此文件位于64位系统的\Windows\Boot\EFI目录下名称为bootmgfw.efi)。 另外提及UEFI就不得不提及到分区相关,在BIOS下我们分区采用MBR分区,而UEFI默认采用GPT分区(事实上Windows 8以后是支持MBR分区的,但此支持不是直接提供的,如果您在UEFI下使用MBR分区来安装系统依旧会报错)。如果您是裸机安装系统,那么当您使用UEFI方式启动原版PE进行分区默认就是GPT分区,您无需关心具体如何分区,PE将自动为您创建必要的启动分区(FAT32格式,用于存放引导文件)以及MSR(微软保留分区)通常还有一个恢复分区用于存放RE(恢复环境)。顺便一提,如果是BIOS模式启动,PE也会创建一个小分区用于存放引导甚至RE(恢复环境)。这些分区都是隐藏的,建议您不要破坏这种结构否则一些功能将不可用(例如对系统盘的加密),也保证了引导文件不被误操作(例如被误压缩)。这里不建议您为了改变引导方式而去修改分区模式,这项操作具有一定风险。如果您已经能非常好的掌握分区相关知识,那么我相信这种操作对您自然亦不在话下。如果只是一知半解则可能造成无法挽回的问题,所以在这里暂不提供这个操作的实施方法。 UEFI实际是简化我们的操作,至少相对BIOS来说他是更加易用的东西,但是多数了没有理解其原理故而把UEFI想象的很麻烦,也有许多人选择了错误的方式而把问题复杂化了。 再来说说多系统并存,实际上多系统并存的实现就是依靠修改配置而在不同系统的启动管理器间切换。如果两个系统的启动管理器可以共用(例如Win7和Win8双系统),那么只要在配置文件上有针对不同系统的配置即可。这也使得多系统在引导出现故障时可能全部无法正常开机,如果您需要一个备用系统那么请把它们安装在不同的存储设备上(重点是引导要在不同设备上)。 最后要提及一点,主流的Win7盗版激活手段实际上是在bootmgr前增加了第三方启动管理器以加载SLIC表到内存中,因此偶尔也会抽风让你的电脑无法正常开机(这个概率是非常低的,不必过于杞人忧天)。 一些特殊的启动方式 (一)从VHD、VHDX启动 高版本的Windows 7(8)支持从VHD(VHDX)来启动系统。VHD是虚拟硬盘文件(VHDX是新版本,需要Win8以上才支持),在我们的计算机上他就是一个文件但却可以一块硬盘来使用。您可以利用他实现硬盘或分区级别的操作,例如bitlocker加密。同时我们可以把操作系统安装在上面,这样备份或还原起来非常方便,同时如果您能灵活其可差分磁盘的特性则能带来实际硬盘无法比拟的功能。不过这都是后话,在安装篇您需要先学会怎么来安装。 将计算机启动到PE中(没有特殊什么这里都是指的原版镜像中的PE),在给实际硬盘分好区之后我们可以按Shift+F10进入命令行。我们可在diskpart工具内完成对VHD(VHDX)文件的处理。下面为示例: diskpart create vdisk file=c:\win7.vhd maximum=20480 type=expandable select vdiskfile=c:\win7.vhd attach vdisk create partition primary format fs=ntfs quick label=system assign letter=y exit Imagex /apply d:\sources\install.wim5 y: BCDBOOT y:\Windows /l ZH-CN 上述命令仅供参考,您需要根据实际情况调整。在Win7时你需要额外下载官方的imagex工具。在Win8上您可以使用dism命令取代。 (二)Windows To Go 对此种方式我们只是单纯的介绍一下,其实际应用意义不大。Windows To Go是Windows 8以上的企业版系统带有的功能,它可以将系统完整的转入高速U盘中使用(这与PE的实现原理并不一致)。其设计初衷是为了专业人士能够在各种地方恢复到自己熟悉的工作环境。但是这种方案一来对U盘要求较高,另外更换电脑使用时需要很长的准备时间。虽然我们也有办法让他在低速U盘流畅使用,但实用程度还是不足。目前我们有byod相关技术可以完美的替代此功能,故此处不再介绍。 (三)WIMBoot 这项技术是在最新的Windows 8.1 with update中才出现。虽然与PE一样是从WIM文件来启动但二者的实现完全不同。其设计初衷是为了在硬盘空间有限的机器上减少系统自身的空间占用,对大容量用户来说并不值得推荐。虽然实验表明这项技术可以用在BIOS与HDD上,但还是建议您使用UEFI与SSD。其安装过程实际就是导出WIM映像、应用映像到目标分区(与映像在不同分区)和建立引导,因此也对应下列三个命令。我们可以启动到Windows 8.1 with update原版镜像的PE环境中或者在具备最新版本DISM、BCDBOOT的系统上运行类似下列命令。 DISM.exe/Export-Image /SourceImageFile:D:\sources\install.wim /SourceIndex:1 /DestinationImageFile:F:\wimboot.wim /WIMBoot DISM.exe/Apply-Image /ImageFile:F:\wimboot.wim/Index:1 /ApplyDir:G:\ /WIMBoot BCDBOOT.exe G:\windows /l ZH-CN /s E: /f UEFI 命令中的路径请根据自己的实际情况修改。 网络安装方式 从网络来安装系统的技术实际上远早于从U盘来安装系统,即便是上个世纪的古董也可以实现。更多的时候我们是利用网络来进行批量安装系统,但此处我们只谈及基本实现方案,对批量工作我们还需要进一步学习定义自动部署脚本,这其实是另外的话题了。如果您不是专业的从业人员并不会需要这样的技术,本文始终只是谈论对单一计算机的Windows系统安装。 先决条件: DHCP服务器 文件传输服务器(TFTP或WDS等服务器) 域控制器(可选) 本示例将采用Windows Server 2012(R2)作为服务端并使用自带的WDS功能进行操作。您自然也可以选择第三方的解决方案但此处不做探讨。另外如果您使用Windows Server 2008 R2并使用WDS,那么域控制器将是必选项目。由于我们并不需要域架构,因此我们不选择这个版本。同时2012以上的版本提供了对UEFI、ARM的支持,甚至是从网络部署VHD系统的图形化操作,因此我们没有理由使用旧版。 首先您需要安装一台Windows Server 2012以上的服务器,安装方法同普通PC故不再复述。并且服务端请使用固定的局域网IP并做好适当的子网划分(本次实验不跨子网操作,因为这可能需要涉及一些网络方向的知识,并且通常我们也没必要跨子网或VLAN操作)。同时我建议您关闭IPv6避免不必要的问题。 image.png 接下来我们需要从服务器管理器(仪表板)上添加DHCP服务器和WDS服务器角色。 image.png 安装完成后您需要确认最后的向导操作。 image.png 首先我们应该配置DHCP的作用域 image.png 我相信您的智商不至于需要一步步的截图,在此列出几个关键点,如果不清楚您可以保持默认。 image.png image.png image.png 接下来是对WDS服务器的配置 image.png image.png 接下来建议您让它响应所有客户端请求。同时建议您在属性中修改如下 image.png 添加至少一个的启动映像(PE)和安装映像,启动映像位于系统映像的sources文件下,名称为boot.wim,安装映像则是install.wim。 image.png 注意:PE和安装镜像没有严格的对应关系,通常高版本的PE可以安装低版本的系统。故而推荐您添加Windows8.1 with update中的PE(32位、64位各一个)到此处。另外下方还有驱动选项,如果PE不能正常驱动您的网卡和硬盘,那么安装将无法继续,您可以添加适合您的驱动后再将驱动添加到启动映像中。如果您要进行批量部署,您可能还需要使用到捕获映像和发现映像的功能。 image.png 多播(又称组播)传输在我们面向单一计算机的安装中并没有用到,在批量安装时您可以建立多播以节省带宽,向导会提示您如何配置,这并无难以理解的地方。 最后不要忘记启动服务 image.png 接下来您需要做的是物理上的链接,请将目标计算机通过交换机或者交叉线连接到服务器(现今的网卡您已可以直接使用直通线暨我们通常所说的网线来连接)。连接后将计算机设置为从网络启动即可。您将看到类似下面的启动过程: image.png 如果您的网卡支持UEFI启动,那么接下来的过程速度会快得多。 image.png 下面您将需要输入合适的凭证,虽然这里我们没有用到域环境,但是您必须使用域用户的格式来输入,格式为服务端的“计算机名\用户名” image.png 接下来的操作将与普通安装方法一致,我们不再截图说明。 【二次提醒】<u>http://pan.baidu.com/s/1pJv01mF</u>,这里是onenote版本和pdf版本的教程和一些可能用到的资源合集,资源内容可能会不定时更新。onenote版本或PDF版本可以避免排版上造成的错误并包含一些不当之处的更正。
很多时候为了方便,搭配wamp或者wnmp环境的时候,直接在windows系统搭建就好了,而且更方便的是直接用集成环境phpstudy,直接了当。这个对于初学者来说,可以这样子做,但是对于一些摸索php好久的同学,其实都没什么挑战性了,更多的是,linux都没去学着的话,更容易忘记。说到lamp或者lnmp,有些同学说我用一键安装就好了,确实,现在的确是很方便,有一键安装包,地址:https://lnmp.org,按照这个网站的安装步骤就可实现了。 但是我还是想体验一下CentOS7.0安装LAMP或者LNMP,最近又摸索了一下,收藏在本公众号里,以后遇到安装的都可以拿出来看看。根据个人的喜好,你们有需要的也可以学习学习的。 CentOS7的安装(素材资料整理自博客) 1)、通过VMware创建虚拟机(这一步不解释) 、成功引导系统后,会出现下面的界面 image 界面说明: Install CentOS 7 安装CentOS 7 Test this media & install CentOS 7 测试安装文件并安装CentOS 7 Troubleshooting 修复故障 这里选择第一项,安装CentOS 7,回车,进入下面的界面 image 选择语言:中文-简体中文(中国) #正式生产服务器建议安装英文版本 image 继续 image 选择-系统-安装位置,进入磁盘分区界面 image 选择-其它存储选项-分区-我要配置分区,点左上角的“完成”,进入下面的界面 image 分区前先规划好 swap #交换分区,一般设置为内存的2倍 / #剩余所有空间 备注:生产服务器建议单独再划分一个/data分区存放数据 image 点左下角的“+”号 挂载点:swap 期望容量:2048 添加挂载点,如下图所示 image 继续点左下角的“+”号 挂载点:/ 期望容量:18.43GB #剩余所有空间 添加挂载点,如下图所示 image 点左上角的“完成”,进入下面的界面 image 接受更改,进入下面的界面 image 开始安装 #注意“软件”-“软件选择”,默认是最小安装,即不安装桌面环境,可以自己设置。 建议选择最小安装即可,最小安装方式安装完成后开机即为命令行模式 设置网络 image 点击,打开网络,注意,这里首先要设置虚拟机的网络为桥接模式。 进入下面的界面 image 选择-用户设置-ROOT密码,进入下面的界面 image 设置Root密码 如果密码长度少于8位,会提示要按“完成”两次来确认,安装继续 image 安装完成之后,会进入下面的界面 image 点重启 image 系统重新启动 image 进入登录界面 image 账号输入root 回车 再输入上面设置的root密码回车 系统登录成功 远程登录,这里我使用Xsell工具 输入命令ifconfig,出来以下信息,红框里的就是你要远程登录的ip地址 image 打开Xsell工具,打开新连接,输入主机地址 image 输入用户名 image 输入密码 image 到这里远程登录已经可以用了 接下来安装Apache,php,mysql,我这里安装的是lamp。 1)、安装Apache Apache软件的软件包名称叫做httpd,因此,要安装Apache软件,就使用下述命令: [root@localhost ~]# yum install httpd 当出现提示的时候一路 y +回车就OK了 image 如上图所示,安装的Apache 软件版本为2.4版。根据红帽官方文档说明,RHEL 7 (或CentOS 7)上可用的Apache版本正是2.4版的。 安装完成后,Apache是以httpd服务的形式存在的。因此,要启动Apache并将其设置为开机启动,就使用命令: [root@localhost ~]# systemctl start httpd.service[root@localhost ~]# systemctl enable httpd.service 然后,检查httpd服务状态: [root@localhost ~]# systemctl status httpd.service image 如上图所示,“enabled”表示httpd服务已设为开机启动,“active(running)”则表示httpd服务正在运行中。 这样的话,HTTP协议就已被启动起来了,由于HTTP协议使用到tcp端口80,因此防火墙要放通tcp端口80: [root@localhost ~]# firewall-cmd --zone=public --add-port=80/tcp --permanent 重启防火墙以让更改立刻生效: [root@localhost ~]# firewall-cmd --reload 使用以下命令检查配置是否成功: [root@localhost ~]# firewall-cmd --list-all image 如上图所示,tcp端口80已放通。 然后这个时候,就可以在物理机上使用浏览器来访问刚刚搭建的web服务器了。不过,因为这个时候还未创建任何页面,所以它显示的是Apache软件自带的测试页面: 通过命令ip addr查询当前系统的ip地址,得到ip地址后再物理机浏览器地址栏输入该ip地址 image 2)安装PHP 使用以下命令安装PHP软件: [root@localhost ~]# yum install php image 从上图可以看到,安装的PHP版本为5.4版。这个是centOS7自带的版本,这里我把它升级到5.6版本,你们也可以升级为PHP7版本的。 进入终端后查看php版本 php -v PHP 5.4.16 (cli) (built: Apr 12 2018 19:02:01) Copyright (c) 1997-2013 The PHP GroupZend Engine v2.4.0, Copyright (c) 1998-2013 Zend Technologies 执行下面的命令升级软件仓库 rpm -Uvh https://mirror.webtatic.com/yum/el7/epel-release.rpmrpm -Uvh https://mirror.webtatic.com/yum/el7/webtatic-release.rpm 执行下面的命令删除php yum remove php-common 然后像安装那样问你是否继续的,输入yes即可 安装php 5.6版本(php56w-devel这个不是必需的) yum install -y php56w php56w-opcache php56w-xml php56w-mcrypt php56w-gd php56w-devel php56w-mysql php56w-intl php56w-mbstring 重启httpd service httpd restart 查看最新的版本 php -v 现在应该是5.6了! 安装mysql 1.新开的云服务器,需要检测系统是否自带安装mysql # yum list installed | grep mysql 2.如果发现有系统自带mysql,果断这么干 # yum -y remove mysql-libs.x86_64 3.随便在你存放文件的目录下执行,这里解释一下,由于这个mysql的yum源服务器在国外,所以下载速度会比较慢,还好mysql5.6只有79M大,而mysql5.7就有182M了,所以这是我不想安装mysql5.7的原因 # wget http://repo.mysql.com/mysql-community-release-el6-5.noarch.rpm 4.接着执行这句,解释一下,这个rpm还不是mysql的安装文件,只是两个yum源文件,执行后,在/etc/yum.repos.d/ 这个目录下多出mysql-community-source.repo和mysql-community.repo # rpm -ivh mysql-community-release-el6-5.noarch.rpm 5.这个时候,可以用yum repolist mysql这个命令查看一下是否已经有mysql可安装文件 #yum repolist all | grep mysql 6.安装mysql 服务器命令(一路yes): # yum install mysql-community-server 7.安装成功后 # service mysqld start 8.由于mysql刚刚安装完的时候,mysql的root用户的密码默认是空的,所以我们需要及时用mysql的root用户登录(第一次回车键,不用输入密码),并修改密码 # mysql -u root# use mysql;# update user set password=PASSWORD("这里输入root用户密码") where User='root';# flush privileges; 9.查看mysql是否自启动,并且设置开启自启动命令 # chkconfig --list | grep mysqld# chkconfig mysqld on 10.mysql安全设置(系统会一路问你几个问题,看不懂复制之后翻译,基本上一路yes): # mysql_secure_installation 以下是讲解授权远程登录,以Navicat工具为主 授权远程访问: 登陆: [root@MiWiFi-R1CL-srv ~]# mysql -u root -pEnter password: ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)[root@MiWiFi-R1CL-srv ~]# mysql -u root -pEnter password: Welcome to the MySQL monitor. Commands end with ; or \g.Your MySQL connection id is 3Server version: 5.6.40 MySQL Community Server (GPL)Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.Oracle is a registered trademark of Oracle Corporation and/or itsaffiliates. Other names may be trademarks of their respectiveowners.Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. 使用mysql数据库(真正的数据库,而非数据库软件),将所有数据库的所有表(.)的所有权限(all privileges),授予通过任何ip(%)访问的root用户,密码为123456,最后刷新(flush privileges)即可。 [图片上传中...(image-b0b9d9-1531740634272-3)] 开放防火墙端口: 通过vim修改/etc/sysconfig/iptables,添加一行(这里是为了简单添加一行,更多防火墙知识请自行学习): image 重启防火墙: image 在windows下,我用 navicat测试: image 远程连接成功。
1.substr(源字符串,其实位置[,长度])-截取字符串返回部分字符串 <?php $str ="phpddt.com"; echo substr($str,2);//pddt.com echo substr($str,2,3);//pdd echo substr($str,-2);//om 负数从结尾开始取 ?> 但是当你截取中文字符串的时候很容易出现乱码,因为一个汉字是两个字节,而一个英文字母是一个字节。解决办法如下: 2.mb_substr(),使用方法和substr相同,不过要开启php.ini里面extension=php_mbstring.dll扩展,不用担心,一般的空间商都会开启这个扩展的。 <?php echo mb_substr("php点点通",1,3,"UTF-8");//hp点 ?> 代码如下: substr(string,start,length) 其中start的参数 正数 - 在字符串的指定位置开始 负数 - 在从字符串结尾的指定位置开始 0 - 在字符串中的第一个字符处开始 strstr() 函数搜索一个字符串在另一个字符串中的第一次出现。 该函数返回字符串的其余部分(从匹配点)。如果未找到所搜索的字符串,则返回 false。 strstr('abc@jb51.net', '@', TRUE); //参数设定true, 返回查找值@之前的首部,abc strstr( 'abc@jb51.net', '@'); //默认返回查找值@之后的尾部,@jb51.net 网上也有很多中文字符串截取教程,实现起来比较复杂,感觉还是用php自带的函数实现起来比较好。整理的网络资料(php代码)如下: (1)截取GB2312中文字符串 <?php //截取GB2312中文字符串 function mysubstr($str, $start, $len){ $tmpstr =""; $strlen = $start + $len; for($i =0; $i < $strlen; $i++){ if(ord(substr($str, $i,1))>0xa0){ $tmpstr .= substr($str, $i,2); $i++; }else $tmpstr .= substr($str, $i,1); } return $tmpstr; } echo mysubstr("php点点通",1,5);//php点 ?> (2)截取utf8编码的多字节字符串 <?php //截取utf8字符串 function utf8Substr($str, $from, $len) { return preg_replace('#^(?:[\x00-\x7F]|[\xC0-\xFF][\x80-\xBF]+){0,'.$from.'}'. '((?:[\x00-\x7F]|[\xC0-\xFF][\x80-\xBF]+){0,'.$len.'}).*#s', '$1',$str); } echo utf8Substr("php点点通",1,5);//hp点点通 ?> (3)支持 utf-8、gb2312都支持的汉字截取函数 <?php //同时支持 utf-8、gb2312都支持的汉字截取函数 ,默认编码是utf-8 function cut_str($string, $sublen, $start =0, $code ='UTF-8') { if($code =='UTF-8') { $pa ="/[\x01-\x7f]|[\xc2-\xdf][\x80-\xbf]|\xe0[\xa0-\xbf][\x80-\xbf]|[\xe1-\xef][\x80-\xbf][\x80-\xbf]|\xf0[\x90-\xbf][\x80-\xbf][\x80-\xbf]|[\xf1-\xf7][\x80-\xbf][\x80-\xbf][\x80-\xbf]/"; preg_match_all($pa, $string, $t_string);if(count($t_string[0])- $start > $sublen)return join('', array_slice($t_string[0], $start, $sublen))."..."; return join('', array_slice($t_string[0], $start, $sublen)); } else { $start = $start*2; $sublen = $sublen*2; $strlen = strlen($string); $tmpstr ='';for($i=0; $i<$strlen; $i++) { if($i>=$start && $i<($start+$sublen)) { if(ord(substr($string, $i,1))>129) { $tmpstr.= substr($string, $i,2); } else { $tmpstr.= substr($string, $i,1); } } if(ord(substr($string, $i,1))>129) $i++; } if(strlen($tmpstr)<$strlen ) $tmpstr.="..."; return $tmpstr; } } $str ="php点点通提供原创php教程"; echo cut_str($str,8,0);//php点点通提供... ?>
最近在玩Laravel实现定时任务,这个是示例代码,可以参照这个实例。有需要的可以看看 定时任务是后端开发过程中一项十分常见的需求,常出现在数据统计、垃圾信息清理等场景中。Laravel 提供了一整套的定时任务工具,让我们只需要专注地完成逻辑,剩下的基础工作将由它来承担。 基本用法 生成命令 php artisan make:command AreYouOK 5.2 及之前的版本,此命令为 php artisan make:console xxx 编辑命令 编辑 app/Console/Commands/AreYouOK.php 文件,修改如下几处: ... ... protected $signature = 'areyou:ok'; // 命令名称 protected $description = '雷军,科技圈最会唱歌的男人'; // 命令描述,没什么用 public function __construct() { parent::__construct(); // 初始化代码写到这里,也没什么用 } public function handle() { // 功能代码写到这里 } 注册命令 编辑 app/Console/Kernel.php 文件,将新生成的类进行注册: protected $commands = [ \App\Console\Commands\AreYouOK::class, ]; 编写调用逻辑: protected function schedule(Schedule $schedule) { $schedule->command('areyou:ok') ->timezone('Asia/Shanghai') ->everyMinute(); } 上面的逻辑是每分钟调用一次。Laravel 提供了从一分钟到一年的各种长度的时间函数,直接调用即可。 把这个 Laravel 项目注册到系统的 cron 里 编辑 /etc/crontab 文件,加入如下代码: * * * * * root /usr/bin/php /var/www/xxxlaravel/artisan schedule:run >> /dev/null 2>&1 上面一行中的 /var/www/xxxlaravel 需要改为实际的路径。 fire 重启 cron 激活此功能:systemctl restart crond.service,搞定!
在做用户注册和个人中心的安全管理时常常需要用到短信发送验证码,下面这篇文章主要给大家介绍了关于laravel中短信发送验证码的实现方法,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴,下面随着小编来一起学习学习吧。 前言 前段时间想实现一个短信验证码的功能,但是卡了很长时间。 首先我用的是阿里云的短信服务业务,其首次接入流程如下: image 在阿里云上开通短信服务后需要做的: 1,申请签名 2,申请模板 3,创建Accesskey ,值得说的是,可以通过阿里云提供的子用户进行Accesskey的创建,这样可以更安全 4,充值 laravel有很多的进行短信业务的扩展包,之前我用的是阿里大于,使用如下: 1,从终端或者命令进入您的项,运行:composer require iscms/alisms-for-laravel 2,将:iscms\Alisms\AlidayuServiceProvider::class加入config\app.php的Providers下 类似: image 3,运行:php artisan vendor:publish,这样会在config文件夹下新增一个alisms.php文件,内容如下: <?php return [ 'KEY' =>env('ALISMS_KEY',null), 'SECRETKEY'=>env('ALISMS_SECRETKEY',null), ]; 4,在.env文件中写入: ALISMS_KEY=23305789 ALISMS_SECRETKEY=************** 注意:ALISMS_KEY和ALISMS_SECRETKEY就是阿里云生成的访问秘钥成对(AccessKeyId 与 AccessKeySecret) 开始使用: 1,在您需要调用短信服务的控制器中引入SMS: use iscms\Alisms\SendsmsPusher as Sms; ... public function __construct(Sms $sms) { $this->sms=$sms; } public function index() { $result=$this->sms->send("$phone","$name","$content","$code"); } 参数说明:phone,name,content,code $phone 指接受短信方的短信号码, $name 指短信签名 可以在阿里大鱼短信签名 http://www.alidayu.com/admin/service/sign 找到 $content 是指短信模板中的变量内容.举个例子 在自己的阿里大鱼模板里面有下面一个短信模板 模板名称: 身份验证验证码 模板ID: SMS_3910275 *模板内容: 验证码[code],您正在进行{product}身份验证,打死不要告诉别人哦! 那么对应的我们的$content 就应该为 { code:"生成的验证码", product:"示例项目"} 到此就可以正常使用,但是不知道为什么,我在使用过程中,控制台返回了code=11的错误码,在淘宝上查证后是因为isv权限的问题,之后我在阿里云上将用户的权限控制开到了最大,但是依旧会出现这个错误,换了一个扩展包还是这个问题,到现在还没有解决,于是我就在laravel中写原生的。 首先从阿里云官网上下载关于短信服务的sdk包 SDK工具包中一共包含了2个类库,一个aliyun-php-sdk-core包,另外一个是alicom-dysms-api包,将这两个包添加到工程类库中依赖。 选择PHP版本的sdk包将压缩包解压,里面有四个文件夹:api_demo,api_sdk,msg_demo,msg_sdk 在laravel项目的app文件夹下新建一个名为libs的文件夹,将api_sdk和msg_sdk复制到libs文件夹下。 找到根目录下的composer.json文件,找到composer.json中定义的classmap选项,写入引入的两个包: image 终端进入项目文件夹中运行: composer dumpautoload 这样子就在laravel中引入了第三方类库。 创建代码文件 我将其简单的封装了一下: <?php // namespace App\Http\Controllers\sms; use Aliyun\Core\Config; use Aliyun\Core\Profile\DefaultProfile; use Aliyun\Core\DefaultAcsClient; use Aliyun\Api\Sms\Request\V20170525\SendSmsRequest; use Aliyun\Api\Sms\Request\V20170525\QuerySendDetailsRequest; use App\Http\Controllers\Controller; // 加载区域结点配置 Config::load(); class SmsController extends Controller { /** * 构造器 * @param string $accessKeyId 必填,AccessKeyId * @param string $accessKeySecret 必填,AccessKeySecret */ public function __construct($accessKeyId="######",$accessKeySecret="#######") { // 短信API产品名 $product = "Dysmsapi"; // 短信API产品域名 $domain = "dysmsapi.aliyuncs.com"; // 暂时不支持多Region $region = "cn-hangzhou"; // 服务结点 $endPointName = "cn-hangzhou"; // 初始化用户Profile实例 $profile = DefaultProfile::getProfile($region, $accessKeyId, $accessKeySecret); // 增加服务结点 DefaultProfile::addEndpoint($endPointName, $region, $product, $domain); // 初始化AcsClient用于发起请求 $this->acsClient = new DefaultAcsClient($profile); } /** * 发送短信范例 * @param [type] $phoneNumbers 必填, 短信接收号码 * @param string $signName 必填, 短信签名,应严格"签名名称"填写, * @param string $templateCode 必填, 短信模板Code,应严格按"模板CODE"填写, * @param [type] $outId 选填, 假如模板中存在变量需要替换则为必填项 * @return [type] [description] */ public function sendSms($phoneNumbers,$signName="XX软件",$templateCode="SMS_XXXXXX",$outId=null) { // 初始化SendSmsRequest实例用于设置发送短信的参数 $request = new SendSmsRequest; // 必填,设置雉短信接收号码 $request->setPhoneNumbers($phoneNumbers); // 必填,设置签名名称 $request->setSignName($signName); // 必填,设置模板CODE $request->setTemplateCode($templateCode); $num = rand(100000,999999); // 可选,设置模板参数 $request->setTemplateParam(json_encode( Array( "code" => "$num" ) )); // 可选,设置流水号 if($outId) { $request->setOutId($outId); } // 发起访问请求 $acsResponse = $this->acsClient->getAcsResponse($request); } /** * 查询短信发送情况范例 * @param [type] $phoneNumbers 必填, 短信接收号码 * @param [type] $sendDate 必填,短信发送日期,格式Ymd,支持近30天记录查询 * @param integer $pageSize 必填,分页大小 * @param integer $currentPage 必填,当前页码 * @param [type] $bizId 选填,短信发送流水号 * @return [type] [description] */ public function queryDetails($phoneNumbers,$sendDate,$pageSize=10,$currentPage=1,$bizId=null) { // 初始化QuerySendDetailsRequest实例用于设置短信查询的参数 $request = new QuerySendDetailsRequest(); $request->setPhoneNumber($phoneNumbers); $request->setSendDate($sendDate); $request->setPageSize($pageSize); $request->setCurrentPage($currentPage); if($bizId) { $request->setBizId($bizId); } $acsResponse = $this->acsClient->getAcsResponse($request); } } 之后用就实例化调用方法就可以了。
总体思路 1.商品关联商品类别,商品类别关联多个商品属性,其中指定某几个商品属性为SKU关键字段。例如,服装类别的颜色、尺码属性。 2.多个SKU商品属性值组合生成唯一的商品SKUID。例如,红色、L=1001,黑色、L=1002。 3.有了商品唯一SKUID就可以方便记录库存了,库存主键:仓库ID,商品ID,SKUID,库存精确到了组合的商品属性。 优缺点 1.灵活,能够应对各种行业商品的需求。 2.商品类别定义时很复杂,一般用户使用起来有难度,可以预置常用的商品类别属性模板解决。 商品模块详细设计 商品模块是支撑整个架构的核心,如果这块没设计好,那么所有后期的复杂的统计需求基本都满足不了。 image 为什么这样子设计属性看这里和这里,把品牌从类目中剥离出来是为了降低程序针对商品属性这块的复杂度。这里通过淘宝的添加宝贝的操作来说明上面的数据结构如何满足下面的需求: image image image PS:本来要截玉兰油沐浴露的图,结果发现淘宝取消了以前选择毫升*买的多送得多组合SKU的添加商品方式,改成了一个SKU就是一个宝贝的编辑手段,呵呵,没办法,只有上面截个衣服的图,下面的数据却是快消品的。淘宝这样做这也是没办法的,这种快消品不同SKU,图片还不能用一样的,而且大部分用户搜索的时候呢,会喜欢直接搜索具体的毫升数,这也给我们提了个醒,不同的类目可能会是不一样的处理方式,就算是服装这种SKU相对标准的类目,也会有说在展示和搜索结果中,会放置一个产品的多个SKU,比如凡客的网站,一件衣服的几个颜色都会出现在类目搜索结果中,增加曝光度,吸引用户点击购买。 页面属性的编程实现可以参考这里。SKU存放在产品SKU表中,按我们的实际需求增加修改字段,比如我的表中多了ProductCode和BarCode字段,SKU的属性会拆分后存入产品基本属性值表,便于搜索或统计等需求。商品的基本属性全部打横存入商品的基本属性表中,那么SKU表的存储如下: image 那么这个item是4013的产品在基本属性值表中的数据存储如下: image 这里我是把所有的属性都打成一条一条存储在这个表中,那么能满足我们在日常业务的属性搜索,统计等需求。按属性搜索,这里必须要注意以下几点: 1.不可能所有的属性都开放给用户或者我们的客户进行搜索,所以我们会在属性名表中有个字段(是否搜索字段)来人工控制哪些属性是搜索属性 2.基本属性是同一个宝贝下面所有SKU都共有的,SKU属性是单个SKU独有的,所以搜索的时候还必须分清楚销售属性(销售属性组成SKU)和基本属性。 3.属性图片的存储我并没有设计,因为我们是做快消品,没有这个需求。但是,如果我做的话我还会是在基本属性值表中加上”是否图片属性,是否使用默认图片,图片URL“3个字段来记录颜色属性。做属性搜索的时候比较方便。 4.产品通过关键字搜索和属性搜索是分开的,两种搜索并不是一种解决方式,比如淘宝,在首页的搜索框是通过分词匹配宝贝标题的关键字,通过关键字的匹配程度,店铺的dsr评分权重来决定搜索结果,而属性搜索的时候则是匹配满足属性条件的宝贝。那属性又分第1点和第2点,所以还是挺麻烦的。
学习PHP的时候,发现程序中的中文在输出的时候会出现乱码的问题,那么为什么会出现这种乱码的情况呢?一般来说,乱码的出现有2种原因,一种是由于编码(charset) 设置错误,导致浏览器以错误的编码来解析,从而出现了满屏乱七八糟的“天书”,第二种就是文件被以错误的编码打开,然后保存,比如一个文本文件原先是GB2312编码的,却以UTF-8编码打开再保存,就会出现乱码的问题。本篇文章,就带大家了解一下,怎么解决php中乱码的问题。 我们将乱码情况分为以下几种,有需要的可以对照下面的几种情况有针对性的解决乱码问题 第一种:解决HTML中中文乱码问题方法 如果你的HTML文件文件出现了乱码问题,那么你可以在head标签里面加入UTF8编码(国际化编码):UTF-8是没有国家的编码,也就是独立于任何一种语言,任何语言都可以使用的。 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> 示例 image 我们现在的HTML5文件,设置编码更为简单,像下面这样 image 第二种、HTML和PHP混合的页面解决方案 如果是HTML和PHP混编,除了按照第一个方法所说的操作之外,还需要在PHP文件的最上面加入这句代码: <?php header("content-type:text/html;charset=utf-8"); //设置编码 ?> 第三种、纯PHP页面的中文乱码问题(数据是静态的) 如果你的PHP页面出现了乱码,只需要在页面的开始处加入下面代码就可以了。 <?php header("content-type:text/html;charset=utf-8"); //设置编码 ?> 第四种、PHP+Mysql中文乱码问题 这个除了按照第三种所说的操作之外,还要在你的数据查询/修改/增加之前加入数据库编码。而且,值得注意的是,这里的UTF8和之前的不一样,中间是没有横线的。 <?php mysql_query('SET NAMES UTF8'); //接下来的就是查出数据或者修改,增加 ?> 如果你使用的MySQL版本在 4.1或更高版本,可以在链接数据库操作后,设置一个字符编码,像下面这样 image UTF-8编码只是其中一种编码,如果不想使用utf-8编码,也可以使用其他编码,只需将UTF-8换成你想使用的编码就可以,目前中文网站开发中主要用的是GB2312和UTF-8 两种编码。 有一点要注意:在需要做数据库操作的php程序前加的 mysql_query("set names '编码'");编码,一定要和php编码一致,如果php编码是gb2312那mysql编码就是gb2312,如果是utf-8那mysql编码就是 utf8,这样插入或检索数据时就不会出现乱码了
本文实例讲述了PHP基于非递归算法实现先序、中序及后序遍历二叉树操作。分享给大家供大家参考,具体如下 概述: 二叉树遍历原理如下: image 针对上图所示二叉树遍历: 1. 前序遍历:先遍历根结点,然后遍历左子树,最后遍历右子树。 ABDHECFG 2.中序遍历:先遍历左子树,然后遍历根结点,最后遍历右子树。 HDBEAFCG 3.后序遍历:先遍历左子树,然后遍历右子树,最后遍历根节点。 HDEBFGCA 实现方法: 先序遍历:利用栈先进后出的特性,先访问根节点,再把右子树压入,再压入左子树。这样取出的时候是先取出左子树,最后取出右子树。 function preorder($root){ $stack = array(); array_push($stack, $root); while(!empty($stack)){ $center_node = array_pop($stack); echo $center_node->value; // 根节点 if($center_node->right != null) array_push($stack, $center_node->right); // 压入右子树 if($center_node->left != null) array_push($stack, $center_node->left); // 压入左子树 } } 中序:需要从下向上遍历,所以先把左子树压入栈,然后逐个访问根节点和右子树。 function inorder($root){ $stack = array(); $center_node = $root; while(!empty($stack) || $center_node != null){ while($center_node != null){ array_push($stack, $center_node); $center_node = $center_node->left; } $center_node = array_pop($stack); echo $center_node->value; $center_node = $center_node->right; } } 后序:先把根节点存起来,然后依次储存左子树和右子树。然后输出。 function tailorder($root){ $stack = array(); $outstack = array(); array_push($$stack, $root); while($empty($stack)){ $center_node = array_pop($stack); array_push($outstack, $center_node); if($center_node->right != null) array_push($stack, $center_node->right); if($center_node->left != null) array_push($stack, $center_node->left); } while($empty($outstack)){ $center_node = array_pop($outstack); echo $center_node->value; } }
本文实例讲述了php实现的微信分享到朋友圈并记录分享次数功能。分享给大家供大家参考,具体如下: 1.引入JS文件 2.通过config接口注入权限验证配置 3.通过ready接口处理成功验证 4.通过error接口处理失败验证 JSDK档说明:https://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html (1) <script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script> (2)页面加入获取webconfig验证信息的值 <?php $url=dirname(dirname(dirname(dirname(dirname(dirname(dirname(__FILE__))))))); $url=$url.'/addons/lb_vote/jssdk.php'; include $url; $jsdk=new JSSDK('wxa3816b432f7291ba','e469db86bec9661650362dc2f9df8956'); $signPackage = $jsdk->GetSignPackage(); ?> (3)验证config wx.config({ debug: false, appId:'<?php echo $signPackage["appId"];?>', // 必填,公众号的唯一标识 timestamp:<?php echo $signPackage["timestamp"];?>, // 必填,生成签名的时间戳 nonceStr: '<?php echo $signPackage["nonceStr"];?>', // 必填,生成签名的随机串 signature:'<?php echo $signPackage["signature"];?>',// 必填,签名,见附录1 jsApiList: ['checkJsApi','onMenuShareTimeline'] // }); (4)微信分享到朋友圈接口 wx.ready(function(){ wx.onMenuShareTimeline({ title: '测试分享朋友圈功能', // 分享标题 link: "{php echo 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];}", // 分享链接 imgUrl: '{php echo $_W['siteroot'];}{$photo}', // 分享图标 success: function () { // 用户确认分享后执行的回调函数 记录分享的次数 $.ajax({ url:"{php echo $this->createMobileUrl('Index',array('op'=>'share'))}", type:'post', data:"id="+{$userinfo['id']}+"&rid="+{$userinfo['rid']}, dataType:'json', success:function(data){ if(data.flags==1){ alert(data.msg); }else if(data.flags==2){ alert(data.msg); location.href="{php echo $this->createMobileUrl('Index',array('op'=>'display','id'=>$id))}" rel="external nofollow" ; } } }); }, cancel: function () { // 用户取消分享后执行的回调函数 alert('取消分享成功!'); } }); }); (5)验证错误时执行的函数 wx.error(function(res){ alert(res); }); (6)PHP端更新数据库,记录分享次数 返回处理信息给用户 if($op=='share'){ $voteinfo=pdo_fetch("SELECT *FROM ".tablename('lb_vote_info')." WHERE rid = :rid and id=:id and uniacid=:uniacid and pass=:pass", array(':rid' => $_GPC['rid'],':uniacid'=>$_W['uniacid'],':pass'=>1,'id'=>$_GPC['id'])); $sharenum=intval($voteinfo['sharenum'])+1; $data=array( 'sharenum'=>$sharenum, ); $res=pdo_update('lb_vote_info', $data, array('id' =>$_GPC['id'],'uniacid'=>$_W['uniacid'],'rid'=>$_GPC['rid'])); if(!empty($res)){ $msg['msg']='已分享到朋友圈!'; $msg['flags']=2; echo json_encode($msg); }else{ $msg['msg']='分享失败!'; $msg['flags']=1; echo json_encode($msg); } }
在说权限管理前,应该先知道权限管理要有哪些功能: (1)、用户只能访问,指定的控制器,指定的方法 (2)、用户可以存在于多个用户组里 (3)、用户组可以选择,指定的控制器,指定的方法 (4)、可以添加控制器和方法 RBAC(Role-Based Access Control,基于角色的访问控制),就是用户通过角色与权限进行关联。简单地说,一个用户拥有若干角色,每一个角色拥有若干权限。这样,就构造成“用户-角色-权限”的授权模型。在这种模型中,用户与角色之间,角色与权限之间,一般者是多对多的关系。 image 1.数据库的设计 写五张表,首先:用户表、角色表、功能表: image 连接表的表..再来就是角色功能表与用户角色表: image 2.管理员的管理页面, (1).分别显示用户名和角色名 (2).根据下拉用户名的变化,更改相应复选框中的角色 (3).修改用户角色时,先要把用户对应角色表,这个用户所有的信息删除,再把取到的用户名和角色代号新添加。 利用下拉列表:嵌入php查询并遍历出来,以下拉列表的方式显示出来 <select id="user"> <?php include ("../db.class.php"); $db = new db(); $sql = "select * from qxyh"; $arr = $db->Query($sql); foreach ($arr as $v) { echo "<option value='{$v[0]}'>{$v[2]}</option>"; } ?> </select> 选择角色,用多选框: <div> 请选择角色 <?php $sjs = "select * from qxzw"; $ajs = $db->Query($sjs); foreach ($ajs as $v) { echo "<input type='checkbox' value='{$v[0]}' class='ck'/>{$v[1]} "; } ?> </div> <input type="button" value="确定" id="btn"/> 图: image 当用户发生变化的时候,相应的角色也相应变化,并且改变人员的角色信息,添加保存,添加保存的基本思路是先把数据库里人员对应的角色信息全部删除,然后再取到选中的部分,添加到数据库。 先来让他选中默认角色: <script> //选中默认角色 function xuan() { var uid = $("#user").val(); $.ajax({ url:"chuli.php", data:{uid:uid,type:0}, type:"POST", dataType:"TEXT", success:function(data) { var juese = data.trim().split("|"); //拆分完全都变成代号 var ck = $(".ck"); ck.prop("checked",false); for(var i=0;i<ck.length;i++) { //便利所有的列表 if(juese.indexOf(ck.eq(i).val())>=0) { ck.eq(i).prop("checked",true); } } } }); } </script> 来写他的处理页面: <?php include ("../db.class.php"); $db = new db(); $type = $_POST["type"]; switch ($type) { case 0: $uid = $_POST["uid"]; $sql = "select jid from qxyhzw WHERE uid='{$uid}'"; echo $db->strQuery($sql); break; } 我们看下最后结果,登录成功就会进入主页,登录失败会提示错误 image 再来,保存按钮: <script> //当用户变化的时候去选中相应角色 $("#user").change(function(){ xuan(); }) //点击确定保存角色信息 $("#btn").click(function(){ var uid = $("#user").val(); //找到用户名 var juese = ""; // 找到角色代号 var ck = $(".ck"); //找到所有的checked for(var i=0;i<ck.length;i++) { // 遍历他 if(ck.eq(i).prop("checked")) { // 如果他选中了,两个参数是改他的状态 //娶过来值;加个|分割一下 juese += ck.eq(i).val()+"|"; } } juese = juese.substr(0,juese.length-1); // 去掉最后的| $.ajax({ url:"chuli.php", data:{uid:uid,juese:juese,type:1}, type:"POST", dataType:"TEXT", success:function(data){ alert("修改成功"); } }); }) }); </script> 处理页面: <?php include ("../db.class.php"); $db = new db(); $type = $_POST["type"]; switch ($type) { case 1: $uid = $_POST["uid"]; $juese = $_POST["juese"]; // 首先全部删掉里面的职位 $sdel = "delete from qxyhzw WHERE uid = '{$uid}'"; $db->Query($sdel,0); //拆分取到的字符串 $arr= explode("|",$juese); foreach ($arr as $v) { $sql = "insert into qxyhzw VALUES ('','{$uid}','{$v}')"; $db->query($sql,0); } echo "ok"; break; } 看效果: image 默认选中角色; 更改以后选择保存: image image 管理页面总代码: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>无标题文档</title> <script src="../jquery-1.11.2.min.js"></script> </head> <body> <h1>用户与角色管理</h1> <!--显示所有用户--> <div>请选择用户 <select id="user"> <?php include ("../db.class.php"); $db = new db(); $sql = "select * from qxyh"; $arr = $db->Query($sql); foreach ($arr as $v) { echo "<option value='{$v[0]}'>{$v[2]}</option>"; } ?> </select> </div> <div> 请选择角色 <?php $sjs = "select * from qxzw"; $ajs = $db->Query($sjs); foreach ($ajs as $v) { echo "<input type='checkbox' value='{$v[0]}' class='ck'/>{$v[1]} "; } ?> </div> <input type="button" value="确定" id="btn"/> </body> </html> <script type="text/javascript"> $(document).ready(function(e){ xuan(); //当用户变化的时候去选中相应角色 $("#user").change(function(){ xuan(); }) //点击确定保存角色信息 $("#btn").click(function(){ var uid = $("#user").val(); //找到用户名 var juese = ""; // 找到角色代号 var ck = $(".ck"); //找到所有的checked for(var i=0;i<ck.length;i++) { // 遍历他 if(ck.eq(i).prop("checked")) { // 如果他选中了,两个参数是改他的状态 //娶过来值;加个|分割一下 juese += ck.eq(i).val()+"|"; } } juese = juese.substr(0,juese.length-1); // 去掉最后的| $.ajax({ url:"chuli.php", data:{uid:uid,juese:juese,type:1}, type:"POST", dataType:"TEXT", success:function(data){ alert("修改成功"); } }); }) }); //选中默认角色 function xuan() { var uid = $("#user").val(); $.ajax({ url:"chuli.php", data:{uid:uid,type:0}, type:"POST", dataType:"TEXT", success:function(data) { var juese = data.trim().split("|"); //拆分完全都变成代号 var ck = $(".ck"); ck.prop("checked",false); for(var i=0;i<ck.length;i++) { //便利所有的列表 if(juese.indexOf(ck.eq(i).val())>=0) { ck.eq(i).prop("checked",true); } } } }); } </script> 处理页面总代码: <?php include ("../db.class.php"); $db = new db(); $type = $_POST["type"]; switch ($type) { case 0: $uid = $_POST["zhang"]; $sql = "select jid from qxyhzw WHERE uid='{$uid}'"; echo $db->strQuery($sql); break; case 1: $uid = $_POST["zhang"]; $juese = $_POST["juese"]; // 首先全部删掉里面的职位 $sdel = "delete from qxyhzw WHERE uid = '{$uid}'"; $db->Query($sdel,0); //拆分取到的字符串 $arr= explode("|",$juese); foreach ($arr as $v) { $sql = "insert into qxyhzw VALUES ('','{$uid}','{$v}')"; $db->query($sql,0); } echo "ok"; break; } 3.登入页面: 显示很简单: <form action="drcl.php" method="post"> <div>帐号:<input type="text" name="zhang"/></div> <div>密码:<input type="text" name="mi"/></div> <input type="submit" value="登入"/> </form> 写登入处理 <?php session_start(); include ("../db.class.php"); $db = new db(); $zhang = $_POST["zhang"]; $mi = $_POST["mi"]; $sql = "select mi from qxyh WHERE zhang = '{$zhang}'"; $mm = $db->strQuery($sql)>0; if($mm = $mi && !empty($mi)) { $_SESSION["zhang"] = $zhang; header("location:chaxun.php"); } //else //{ // echo "登入失败"; //} 跳转到主页面,主页面代码: 每个人的主页面都是不一样的 <body> <h1>主页面</h1> <?php session_start(); include ("../db.class.php"); $db = new db(); $zhang = ""; if(empty($_SESSION["zhang"])) { header("location:qx_dr.php"); exit; } //登入者用户名 $zhang = $_SESSION["zhang"]; //根据用户名查角色 $sql = "select jid from qxyhzw WHERE uid = '{$zhang}'"; $aql = $db->Query($sql); //根据角色代号查功能代号 $attr = array(); //定义一个存放功能代号的数组 foreach ($aql as $v) { $jsid = $v[0];// 角色代号 $ssql = "select rid from qxgnzw WHERE jid='{$jsid}'"; $aaql = $db->strQuery($ssql); //拆分 $adai = explode("|",$aaql); foreach ($adai as $h) { array_push($attr,$h); } } $attr = array_unique($attr); //去重 //显示 foreach ($attr as $k) { $ql = "select * from qxgn WHERE code = '{$k}'"; $arr = $db->Query($ql); $arr[0][0]; $arr[0][1]; echo "<div code='{$arr[0][0]}'>{$arr[0][1]}</div>"; } ?> </body> image 用php的用户体验不好,最好还是得用ajax
index.html <!DOCTYPE HTML> <html> <head> <title>反ajax推送</title> <style> .send{color:#555;text-align: left;} .require{color:blue;text-align: right;} .content_box{text-align: center;margin: 20px; border: 1px solid #ddd;padding: 20px;} </style> <script src="http://code.jQuery.com/jquery-1.11.2.min.js"></script> </head> <body> <div class="content_box" id="content_box_title" style="border: none;">消息框</div> <div class="content_box" id="content_box"> </div> <div style="width: 450px;margin: 0 auto;"> <select id="username" style="font-size: 20px;"> <option value="1" selected="selected">1</option> <option value="2">2</option> </select> <input type="text" style="font-size: 20px;" value="" id="send_text"> <button id="btn_send" style="font-size: 20px;">发送</button> <button id="btn_link" style="font-size: 20px">连接</button> </div> <div class="error_tip" id="error_tip" style="color: red;"> </div> <script> $(function(){ //发送消息 $('#btn_send').click(function(){ var send_text = $('#send_text').val(); if(send_text.length <= 0){ $('#error_tip').html('不能输入空值'); }else{ send(send_text); } }); //按回车键发送消息 $('#send_text').on('keyup',function(e){ if(e.keyCode == 13){ $('#btn_send').trigger('click'); } }); //建立通讯链接 $('#btn_link').click(function(){ connect(); var _this = $(this); _this.attr('disabled',true); _this.html('已连接'); }); }); //建立通讯连接函数 function connect(){ $('#content_box_title').html($('#username').val()+'的消息窗口'); $.ajax({ data:{'user':$('#username').val()}, url:'ajaxPush.PHP', type:'get', timeout:0, dataType:'json', success:function(data){ $('#content_box').append('<div class="require">'+data.msg+'</div>'); connect(); } }); } //发送消息函数 function send(massege){ var user =$('#username').val(); $.getJSON('write.php',{'msg':massege,'user':user},function(data){ if(data.sf){ $('#content_box').append('<div class="send">'+massege+'</div>'); $('#send_text').val(''); }else{ $('#error_tip').html('输入保存错误!'); } }); } </script> </body> </html> ajax处理输入 write.php <?php /** * Created by Loading. * Time: 2017/4/18 13:13 * function: */ $filename = dirname(__FILE__).'/data.txt'; $isread_file = dirname(__FILE__).'/isread.txt'; $user = dirname(__FILE__).'/user.txt'; //写入消息,消息未读,谁发送的消息 file_put_contents($filename,$_GET['msg']); file_put_contents($isread_file,'0'); file_put_contents($user,$_GET['user']); echo json_encode(array('sf'=>true)); 长轮询推送 ajaxPush.php <?php /** * Created by Loading * Time: 2017/4/18 13:12 * function: */ $filename = dirname(__FILE__).'/data.txt'; $isread_file = dirname(__FILE__).'/isread.txt'; $userfile = dirname(__FILE__).'/user.txt'; $get_user = $_GET['user'] == '1'?'2':'1'; $msg=''; while(1){ $msg = file_get_contents($filename); $isread = file_get_contents($isread_file); $user = file_get_contents($userfile); //是对方发送的消息,设置消息已读,退出循环。 if($isread == '0' && $get_user == $user){ file_put_contents($isread_file,'1'); break; } sleep(1); } echo json_encode(array('msg'=>$msg));
//ORDER BY 后可加2个字段,用英文逗号隔开。 //f1用升序, f2降序,SQL该这样写 ORDERBY f1, f2 DESC //也可以这样写,更清楚: ORDERBY f1 ASC, f2 DESC //如果都用降序,必须用两个desc ORDERBY f1 DESC, f2 DESC
$old['xxx'] = (int) $_POST['ooo']; $res = serialize($old); 取出: var_dump(unserialize($res));die; 手册:http://php.net/manual/zh/function.serialize.php 序列化表单(Ajax中):https://blog.csdn.net/xinghuo0007/article/details/72654817
js $(function () { var $choose = $("#choose input"); $("#all").click(function () { $choose.each(function () { $(this).prop("checked", true); }); }); $("#not").click(function () { $choose.prop("checked", false); }); $("#reverse").click(function () { $choose.each(function () { $(this).prop("checked", !$(this).prop("checked")); }); }); //批量操作 $("#alldel").click(function () { var f = false; //得到要删除的主键id //用于存要删除的选中的id值 var arr = []; //得到一组checkbox 相当于数组 var ck = document.getElementsByName("spu_id"); //循环这一组checkbox让每一个checkbox选中 for (var i = 0; i < ck.length; i++) { if (ck[i].checked == true) { //代表选中 arr.push(ck[i].value); f = true; } } //跳到删除的servlet里去 if (f == true) { if (confirm("您确认要全部下架吗?")) { alert(arr); } } else { alert("请至少选中一条进行批量删除"); } }) }); html <input id="all" type="button" value="全选" /> <input id="not" type="button" value="全不选" /> <input id="reverse" type="button" value="反选" /> <input id="alldel" type="button" value="批量上架" />
image CREATE TABLE `order_auto_confirm` ( `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, `order_id` INT(10) UNSIGNED NOT NULL DEFAULT '0', `order_sn` VARCHAR(20) NOT NULL, `execute_time` INT(10) UNSIGNED NOT NULL DEFAULT '0', `order_status` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0' COMMENT '0未确定,1已经确定', `addtime` INT(10) UNSIGNED NOT NULL DEFAULT '0', `update_time` INT(10) UNSIGNED NOT NULL DEFAULT '0', PRIMARY KEY (`id`), UNIQUE INDEX `order_id` (`order_id`), INDEX `execute_time` (`execute_time`) ) COMMENT='订单定期自动确定' COLLATE='utf8_general_ci' ENGINE=MyISAM; 一、 /admin/order.php加入以下代码: elseif($_REQUEST['act'] == 'order_cron') { $act1 = empty($_POST['act1']) ? 0 : $_POST['act1']; if(empty($act1) || !in_array($act1, array('add', 'cancel'))) make_json_response('', -1, '未知请求act1'); $order_id = intval($_POST['order_id']); $order = order_info($order_id); if(empty($order)) make_json_response('', -2, '没有此订单ID'); if($order['order_status']) make_json_response('', -3, '此订单已经确认,不用自动确认'); if($order['pay_status']) make_json_response('', -4, '此订单支付状态已经变动,无法添加任务'); if($act1 == 'add'){ $order_cron_time = empty($_POST['order_cron_time']) ? 0 : $_POST['order_cron_time']; if(empty($order_cron_time)) make_json_response('', -10, '请求的时间错误'); $sql = 'select order_id from '.$ecs->table('order_auto_confirm').' where order_id='.$order_id; $rs = $db->getRow($sql); if($rs['order_id'] == $order_id){ make_json_response('', -30, '此订单任务已经存在,不能重复添加'); } $execute_time = local_strtotime($order_cron_time); $sql = "insert into ".$ecs->table('order_auto_confirm')."(order_id, order_sn, execute_time, order_status, addtime) values(".$order_id.",'".$order['order_sn']."',".$execute_time.", 0, ".local_gettime().")"; $result = $db->query($sql); if($result){ make_json_response('', 0, ''); } make_json_response('', -9, '添加任务计划失败'); }elseif($act1 == 'cancel'){ $sql = 'delete from '.$ecs->table('order_auto_confirm').' where order_id='.$order_id.' and order_status=0 '; $db->query($sql); make_json_response('', 0, ''); } } 二、 在elseif($_REQUEST['act'] == 'info')里加入: //取自动确定订单信息 $sql = 'select order_status, execute_time, addtime, update_time from '.$ecs->table('order_auto_confirm').' where order_id='.$order['order_id']; $cron= $db->getRow($sql); if(!empty($cron)){ if($cron['order_status'] == 1) $cron['update_time'] = sprintf($_LANG['order_auto_croned'], local_date('Y-m-d H:i:s', $cron['update_time'])); else $cron['execute_time']= sprintf($_LANG['order_auto_cron'], local_date('Y-m-d H:i:s', $cron['execute_time'])); } $smarty->assign('cron', $cron); 三、 /includes/modules/cron/order_auto_confirm.php if (!defined('IN_ECS')) { die('Hacking attempt'); } require_once(ROOT_PATH . 'includes/lib_order.php'); $cron_lang = ROOT_PATH . 'languages/' .$GLOBALS['_CFG']['lang']. '/cron/order_auto_confirm.php'; if (file_exists($cron_lang)) { global $_LANG; include_once($cron_lang); }/* 模块的基本信息 */ if (isset($set_modules) && $set_modules == TRUE) { $i = isset($modules) ? count($modules) : 0; /* 代码 */ $modules[$i]['code'] = basename(__FILE__, '.php'); /* 描述对应的语言项 */ $modules[$i]['desc'] = 'order_auto_confirm_desc'; /* 作者 */ $modules[$i]['author'] = 'wjzhhr'; /* 网址 */ $modules[$i]['website'] = 'http://www.wodeqingchun.com'; /* 版本号 */ $modules[$i]['version'] = '1.0.0'; /* 配置信息 */ $modules[$i]['config'] = array( array('name' => 'order_auto_confirm_count', 'type' => 'select', 'value' => '10'), ); return; } $time = gmtime(); //$time = local_gettime(); $limit = empty($cron['order_auto_confirm_count']) ? 5 : $cron['order_auto_confirm_count']; $sql = "SELECT * FROM " . $GLOBALS['ecs']->table('order_auto_confirm') . " WHERE execute_time <= ".$time." and order_status=0 LIMIT $limit"; $autodb= $db->getAll($sql); $i = 0; foreach ($autodb as $key => $val) { $order_id = $val['order_id']; $order_sn = $val['order_sn']; /* 标记订单为已确认 */ $update_status = update_order($order_id, array('order_status' => OS_CONFIRMED, 'confirm_time' => gmtime())); update_order_amount($order_id); /* 记录log */ $action_note = "计划任务:定期自动确定订单,订单号:".$order_sn.",执行状态:".($update_status ? '成功' : '失败'); order_action($order_sn, OS_CONFIRMED, SS_UNSHIPPED, PS_UNPAYED, $action_note, 'system_cron'); /* 如果原来状态不是“未确认”,且使用库存,且下订单时减库存,则减少库存 */ if ($val['order_status'] != OS_UNCONFIRMED && $_CFG['use_storage'] == '1' && $_CFG['stock_dec_time'] == SDT_PLACE) { change_order_goods_storage($order_id, true, SDT_PLACE); } if($update_status) { $i += 1; $sql = "update " . $GLOBALS['ecs']->table('order_auto_confirm') . " set order_status=1, update_time=".$time." where order_id=".$order_id; $db->query($sql); } }$string = '此次共更新:'.$i.'条数据'; echo $string;file_put_contents('./a.txt', $time . '----' . date('Y-m-d H:i:s').$string."\r\n", FILE_APPEND); /** * 更新订单总金额 * @param int $order_id 订单id * @return bool //zuimoban.com */ function update_order_amount($order_id) { include_once(ROOT_PATH . 'includes/lib_order.php'); //更新订单总金额 $sql = "UPDATE " . $GLOBALS['ecs']->table('order_info') . " SET order_amount = " . order_due_field() . " WHERE order_id = '$order_id' LIMIT 1"; return $GLOBALS['db']->query($sql); } ?> 四、 /languages/zh_cn/admin/order.php里加入: // $_LANG['order_auto_croned'] = '此订单于 %s 已被确认'; $_LANG['order_auto_cron'] = '此订单于 %s 进行定时确认'; $_LANG['order_auto'] = '将此订单加入自动定时确认'; $_LANG['order_auto_time'] = '自动确认时间:'; 五、 /admin/themes/order_info.htm在:{$lang.base_info}后面加入: image 在此页面的JS里面加入: function order_cron(order_id, act){ var order_cron_time = 0; if(act == 'add'){ order_cron_time = document.getElementById('order_cron_time').value; if(!order_cron_time){ alert('无法获取时间'); return false; } } Ajax.call('order.php?act=order_cron', 'order_id=' + order_id + '&act1=' + act + '&order_cron_time=' + order_cron_time, order_cron_response, 'POST', 'JSON');}function order_cron_response(res){ if (res.error == 0) { alert('保存成功'); } else { alert(res.message); } return false;} 还有/themes/default/footer.dwt里是否含有:{insert name='query_info'} 这一句,比较重要,前人把这句去掉了,害最模板到处找原因。共涉及5个文件,两个新添加的 我只是个搬运工。侵删。原文:httpwww.ktshou.comportal.phpmod=view&aid=121
image.png if(strpos($info['avatar'],'132132')){ $upgrade2=array(); $upgrade2['avatar'] = str_replace('132132', '132', $info['avatar']); pdo_update('ewei_shop_member', $upgrade2, array('id' => $info['id'])); } 加入代码即可
使用微信获取地址信息是和微信支付一道申请的,微信支付申请通过,就可以使用该功能。 微信商城中,使用微信支付获取用户的收货地址,可以省略用户输入地址信息的繁复流程,提高用户体验。 但是可能是因为牵扯到用户隐私,所以在使用过程中,需要用户自己主动选择使用该功能,并且是通过点击的操作,我们才可以获取到用户的收货地址,这一点是要注意的。 操作流程如下: 用户打开购物车页面,点击结算,跳转到一个微信的oauth2的页面,地址为:https://open.weixin.qq.com/connect/oauth2/authorize 2.oauth2页面将链接redirect到结算页面,使用PHP获取到链接中的code参数,经过处理获取到accessToken值。生成签名,组装成数组参数传递到页面。 3.结算页面使用用户点击事件,结合2中生成的数组参数完成获取地址的功能。这里可以有一个将获取到的地址使用ajax记录到数据库的功能,那么客户下次购物的时候,就不用麻烦了。 详细的讲下需要注意的几点: 1.跳转到微信oauth2的这个步骤,在用户看来是没有多少差别的,但是在程序这里就有很多的事情要做。首先是oauth2页面的参数,其中appid为微信appid,redirect_uri为urlencode后的订单结算页面的地址,response_type为固定的code,scope为固定的snsapi_base,state在这个地方可随意填写,还有一个#wechat_redirect,那么该链接的最终样子为: https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=订单结算地址&response_type=code&scope=snsapi_base&state=随意填写#wechat_redirect 2.用户访问到该地址,被重新定位到追加了code参数订单结算地址,在此页面需要由程序获取到accessToken,注意该accessToken为获取用户信息的accessToken跟另外一个和微信交互的access token不是同一个。 使用GET请求就可以获取该accessToken,可以使用curl或者是file_get_contents。请求地址为: https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=APP_SECRET&code=CODE&grant_type=authorization_code; 这里有一点需要注意,有时候微信会抽风,会连续多次请求订单结算页面,造成accessToken失效,需特殊处理。 这里的签名生成和微信支付里面的签名不一样,这里的要简单很多,只是加密一个字符串,格式为:accesstoken=ACCESSTOKEN&appid=APPID&noncestr=32位随机字符串×tamp=时间戳&url=当前页面的URL,然后对该字符串进行sha1加密。 在前端页面中需要使用一连串的参数来实现获取地址的功能,分别是appID,scope(默认为jsapi_address),signType(默认为sha1),addrSign(上面sha1加密后的字符串),timeStamp(同上文的时间戳),nonceStr(同上文的随机字符串)。 image 3.在前端页面,使用下面的js函数来完成获取用户地址的操作: function get_addr() { WeixinJSBridge.invoke('editAddress',{ "appId" : "<?php echo $sign['appId']?>", "scope" : "jsapi_address", "signType" : "sha1", "addrSign" : "<?php echo $sign['addrSign']?>", "timeStamp" : "<?php echo $sign['timeStamp']?>", "nonceStr" : "<?php echo $sign['nonceStr']?>", },function(res){ if(res.err_msg == 'edit_address:ok') { //将地址信息存入数据库 //将地址信息显示在当前页面 document.getElementById("address_info").innerHTML="<b>收件人:"+res.userName+"</b> <b>"+res.telNumber+"</b><br /> 收货地址:"+res.proviceFirstStageName+res.addressCitySecondStageName+res.addressCountiesThirdStageName+res.addressDetailInfo; } else{ alert("获取地址失败,请重新点击"); } }); } 至此,使用微信获取用户共享地址的开发就完毕了。
名词解释:并发 在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行,但任意一个时刻上只有一个程序在处理机上运行。 我们说的高并发是什么? 上面的定义明显不是我们通常所言的并发,在互联网时代,所讲的并发、高并发,通常是指并发访问。也就是在某个时间点,有多少个访问同时到来通常如果一个系统的日PV在千万以上,有可能是一个高并发的系统,但是有的公司完全不走技术路线,全靠机器堆,这不在我们的讨论范围。 高并发的问题,我们具体该关心什么? QPS:每秒钟请求或者查询的数量,在互联网领域,指每秒响应请求数(指HTTP请求) 吞吐量:单位时间内处理的请求数量(通常由QPS与并发数决定) 响应时间:从请求发出到收到响应花费的时间,例如系统处理一个HTTP请求需要100ms,这个100ms就是系统的响应时间 PV:综合浏览量(Page View),即页面浏览量或者点击量,一个访客在24小时内访问的页面数量,同一个人浏览你的网站同一页面,只记作一次PV UV:独立访问(UniQue Visitor),即一定时间范围内相同访客多次访问网站,只计算为1个独立访客 带宽:计算带宽大小需关注两个指标,峰值流量和页面的平均大小 日网站带宽=PV/统计时间(换算到秒)平均页面大小(单位KB)8 峰值一般是平均值的倍数,根据实际情况来定 QPS不等于并发连接数 QPS是每秒HTTP请求数量,并发连接数是系统同时处理的请求数量 (总PV数80%)/(6小时秒数20%)=峰值每秒请求数(QPS) 80%的访问量集中在20%的时间!!! QPS达到极限,各种情况如何处理? 随着QPS的增长,每个阶段需要根据实际情况来进行优化,优化的方案也与硬件条件、网络带宽息息相关。 QPS达到50 可以称之为小型网站,一般的服务器就可以应付 QPS达到100 假设关系型数据库的每次请求在0.01秒完成 假设单页面只有一个SQL查询,那么100QPS意味这1秒钟完成100次请求,但是此时我们并不能保证数据库查询能完成100次 方案:数据库缓存层、数据库的负载均衡 QPS达到800 假设我们使用百兆带宽,意味着网站出口的实际带宽是8M左右 假设每个页面只有10k,在这个并发条件下,百兆带宽已经吃完 方案:CDN加速、负载均衡 QPS达到1000 假设使用Memcache缓存数据库查询数据,每个页面对Memcache的请求远大于直接对DB的请求 Memcache的悲观并发数在2W左右,但有可能在之前内网带宽已经吃光,表现出不稳定 方案:静态HTML缓存 QPS达到2000 这个级别下,文件系统访问锁都成为灾难 方案:做业务分离,分布式存储 三种高并发解决方案 一、数据库缓存层的优化 什么是数据库缓存? MySQL等一些常见的关系型数据库的数据都存储在磁盘中,在高并发场景下,业务应用对MySQL产生的增、删、改、查的操作造成巨大的I/O开销和查询压力,这无疑对数据库和服务器都是一种巨大的压力,为了解决此类问题,缓存数据的概念应运而生 为什么是要使用缓存? 缓存数据是为了让客户端很少甚至不访问数据库服务器进行数据的查询,高并发下,能最大程度的降低对数据库服务器的访问压力极大地解决数据库服务器的压力 提高应用数据的响应速度 用户请求-->数据查询-->连接数据库服务器并查询数据-->将数据缓存起来(HTML、内存、JSON、序列化数据)-->显示给客户端 用户再次请求或者新用户访问-->数据查询-->直接从缓存中获取数据-->显示给客户端 二、CDN加速 什么是CDN? CDN的全称是Content Delivery Network,即内容分发网络,尽可能避开互联网上有可能影响数据传输速度和稳定性的瓶颈和环节,使内容传输的更快、更稳定 在网络各处放置节点服务器所构成的在现有的互联网基础之上的一层智能虚拟网络 CDN系统能够实时地根据网络流量和各节点的连接、负载状况以及到用户的距离和响应时间等综合信息将用户的请求重新导向离用户最近的服务节点上 使用CDN的优势? 本地Cache加速,提高了企业站点(尤其含有大量图片和静态页面站点)的访问速度 跨运营商的网络加速,保证不同网络的用户都得到良好的访问质量 远程访问用户根据DNS负载均衡技术智能自动选择Cache服务器 自动生成服务器的远程Mirror(镜像)cache服务器,远程用户访问时从cache服务器上读取数据,减少远程访问的带宽,分担网络流量,减轻原站点WEB服务器负载等功能 广泛分布的CDN节点加上节点之间的智能冗余机制,可以有效地预防黑客入侵 三、Web服务器的负载均衡、请求分发 七层负载均衡的实现 基于URL等应用信息的负载均衡 Nginx的proxy是它一个很强大的功能,实现了7层负载均衡 Nginx实现的优点 功能强大,性能卓越,运行稳定 配置简单灵活 能够自动剔除工作不正常的后端服务器 上传文件使用异步模式 支持多种分配策略,可以分配权重,分配方式灵活 Nginx负载均衡 内置策略,扩展策略 内置策略:IP Hash、加权轮询 扩展策略:fair策略、通用hash、一致性hash 加权轮询策略 首先将请求都分给高权重的机器,直到该机器的权值降到了比其他机器低,才开始将请求分给下一个高权重的机器 当所有后端机器都down掉时,Nginx会立即将所有机器的标志位清成初始状态,以避免造成所有的机器都处于timeout的状态 IP Hash策略 Nginx内置的另一个负载均衡的策略,流程和轮询很类似,只是七种的算法和具体的策略有些变化 IP Hash算法是一种变相的轮询算法
ecshop二次开发资料 image.png 链接:https://pan.baidu.com/s/1kWBdeHx 密码:k0we 有帮助的希望点个赞。如果链接失效了可以加QQ:1065628795
https://mp.weixin.qq.com/debug/wxadoc/dev/component/web-view.html image.png <!-- 指向微信公众平台首页的web-view --> <web-view src="https://mp.weixin.qq.com/"></web-view> image.png title修改 image.png
<html> <head> <title></title> </head> <body> <script language=JavaScript> <!-- var caution = false function setCookie(name, value, expires, path, domain, secure) { var curCookie = name + "=" + escape(value) + ((expires) ? "; expires=" + expires.toGMTString() : "") + ((path) ? "; path=" + path : "") + ((domain) ? "; domain=" + domain : "") + ((secure) ? "; secure" : "") if (!caution || (name + "=" + escape(value)).length <= 4000) document.cookie = curCookie else if (confirm("Cookie exceeds 4KB and will be cut!")) document.cookie = curCookie } function getCookie(name) { var prefix = name + "=" var cookieStartIndex = document.cookie.indexOf(prefix) if (cookieStartIndex == -1) return null var cookieEndIndex = document.cookie.indexOf(";", cookieStartIndex + prefix.length) if (cookieEndIndex == -1) cookieEndIndex = document.cookie.length return unescape(document.cookie.substring(cookieStartIndex + prefix.length, cookieEndIndex)) } function deleteCookie(name, path, domain) { if (getCookie(name)) { document.cookie = name + "=" + ((path) ? "; path=" + path : "") + ((domain) ? "; domain=" + domain : "") + "; expires=Thu, 01-Jan-70 00:00:01 GMT" } } function fixDate(date) { var base = new Date(0) var skew = base.getTime() if (skew > 0) date.setTime(date.getTime() - skew) } var now = new Date() fixDate(now) now.setTime(now.getTime() + 365 * 24 * 60 * 60 * 1000) var visits = getCookie("counter") if (!visits) visits = 1 else visits = parseInt(visits) + 1 setCookie("counter", visits, now) document.write("您是第" + visits + "位访问此文章的!") // --> </script> </body> </html>
匹配/tpa=http:/// /\*.*?\*/ 匹配tppabs标签: \btppabs="h[^"]*" 匹配javascript代码: href="javascript:if\(confirm\('htt[^"]*"
最近修改定时任务重新部署后,定时运行后运行结果为0x1,但是手动执行后,任务可以顺利完成。 windows官网解释如下: 0x0: 操作已成功完成 0x1: 调用的函数不正确或调用了未知函数。 因为手动可以执行,所以我排除程序问题,应该是系统权限造成的问题。然后尝试调整运行权限后,顺利执行。 操作如下: 这里写图片描述 运行权限默认的设置是“只在用户登录时运行”,这个设置有个问题就是当服务器重启后,没有登录的情况下,定时任务无法执行。所以我们刚才改成“不管用户是否登录都要运行”,如下图所示: 这里写图片描述 点击确认按钮后,会提示你输入你的密码,如下图所示: 这里写图片描述 输入你当前登录用户的密码后,就设置完成了。 最近修改定时任务重新部署后,定时运行后运行结果为0x1,但是手动执行后,任务可以顺利完成。 windows官网解释如下: 0x0: 操作已成功完成 0x1: 调用的函数不正确或调用了未知函数。 因为手动可以执行,所以我排除程序问题,应该是系统权限造成的问题。然后尝试调整运行权限后,顺利执行。 操作如下: 这里写图片描述 运行权限默认的设置是“只在用户登录时运行”,这个设置有个问题就是当服务器重启后,没有登录的情况下,定时任务无法执行。所以我们刚才改成“不管用户是否登录都要运行”,如下图所示: 这里写图片描述 点击确认按钮后,会提示你输入你的密码,如下图所示: 这里写图片描述 输入你当前登录用户的密码后,就设置完成了。
thinkphp5.0开发中后台return回来的data是个数组,直接alert看不了,alert(JSON.stringify(data));这样的话,就可以看到了
背景 当一个网站从小到大,访问量逐渐增大现有的服务器已经支撑不住,一般的解决方案就是缓存、加服务器、数据库读写分离、实行负载均衡分布式等等,本人对这些技术方案都没有在项目中具体的实践过, 但是一直听同事过说起,利用空闲时间自我学习了解下; 负载均衡 什么是负载均衡,就是当快要承受不住的时候,又给你一台服务器来分担压力,请求会分配到两台服务器上,两台服务器上部署相同的内容相当于一个分身,可以处理相同的事情; Nginx作为负载均衡服务器,用户请求先到达nginx,再由nginx根据负载配置将请求转发至不同的Web服务器 Nginx配置文件 从Nginx官网下载 http://nginx.org/en/download.html 安装Nginx,并找到nginx.conf文件(C:\nginx\conf\nginx.conf); 在http中加入配置: upstream www.woizuqiu.com { server 192.168.1.1:8080 weight=1; server 192.168.1.1:8090 weight=2; } ip_hash轮询方法,不可给服务器加权重,nginx会让相同的客户端ip请求相同的服务器 upstream www.woizuqiu.com { server 192.168.1.1:8080; server 192.168.1.1:8090 max_fails=3 fail_timeout=30s ; ip_hash; } 根据服务器的本身的性能差别及职能,可以设置不同的参数控制。 down 表示负载过重或者不参与负载 weight 权重过大代表承担的负载就越大 backup 其它服务器时或down时才会请求backup服务器 max_fails 失败超过指定次数会暂停或请求转往其它服务器 fail_timeout 失败超过指定次数后暂停时间 server配置如下: server { listen 80; server_name www.woizuqiu.com; #charset koi8-r; #access_log logs/host.access.log main; location / { add_header backendIP $upstream_addr;#被转发到的上游服务器地址 add_header backendCode $upstream_status;#状态码 proxy_pass http://www.woizuqiu.com; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } } 1.查看Nginx版本: C:\nginx>nginx -v2.启动Nginx: C:\nginx>start nginx 启动Nginx需要占用80端口,常见错误:bind() to 0.0.0.0:8080 failed (10013: An attempt was made to access a socket in a way forbidden by its access permissions),需要把系统的80端口关掉, 检查端口:netstat -aon | findstr :803.判断Nginx是否启动: tasklist /fi "imagename eq nginx.exe"4.停止: C:\nginx>nginx.exe -s stop5.重新载入Nginx: C:\nginx>nginx.exe -s reload 来源:http://mp.weixin.qq.com/s/T8sDa9ER0j-OQgppFNy9XA
读写分离与主从复制是提升mysql性能的重要及必要手段,大中型管理系统或网站必用之。一、什么是读写分离与主从复制 先看图 (图1 图片来源于网络) 如上图所示,当web server1/2/3要写入数据时,则向mysql db Master(主服务器)发出写入请求(即写入到master),如果要进入读操作时,则只向从服务器 mysql DB Slave1或2或3发出读取请求。如此将原本读写在同一台服务器的工作量分摊到了一台负责写入,N台负责读取(大部分的网站都是读取请求远大于写入请求),从而从一定程度时实现了负载均衡(如果有N台从服务器,则由主从代理系统自动分配某个具体请求从哪一个从服务器读取)。 读写分离是靠主从复制来实现的。即当一个数据写入到主服务器后,主服务器会将写入信息写入到binlog(二进制日志)里,同时同步(或异步或半同步)到从服务器里。从服务器根据主服务器传来的binlog,生成relay-log(中继日志),然后mysql服务器再用relay-log的信息将数据写入到数据库。 如此做的优点除了实现负责均衡之外,还为我们保留了两份实时热备的数据binlog和relay-log。当服务器发生灾难时,我们可以用他们将数据恢复到任何一个时间点。 二、准备 1、在linux上安装好两台mysql服务器(mysql至少5.5以上),且两台服务器最好在一个机房(如此通过内网进行主从复制,速度远远大于通过外网。如果web服务器也在同一机房,则也可内网访问,还不用向ISP买带宽)。 假定主的IP为10.121.0.110,从的IP为10.121.0.220. 2、关闭两台服务器的防火墙(稍后再配置): service iptables stop (这是centos6.5关闭方法,其他系统请问度娘) 3、如果你没有创建数据库,则进行如下操作 (1)在主服务器上登录mysql mysql -uroot -p你的密码 (2)创建数据库 mysql> create database test1; mysql> create database test2; (3)如果已经有历史数据,则将历史数据备份成sql文件上传到主服务器,运行如下命令 mysql> source /disk/test1.sql;('/disk/test1.sql '换成你自己的路径即可) 三、主服务器配置 mysql已经提供了完美的读写分离与主从复制支持,我们只需要作如下设置即可。 1、配置my.cnf vi /etc/my.cnf (1)去掉log-bin=mysql-bin前的“#”号。这一行的意思是允许mysql使用binlog,同时为主从复制打开了大门。这是关键中的关键中的关键。 (2)如果有多个数据库,则添加如下行: binlog-do-db=数据库名1 binlog-do-db=数据库名2 binlog-do-db=数据库名3 binlog-ignore-db=mysql(忽略mysql自身用的数据库) (3)查看server-id是后的数字并记住。slave(从服务器)的server-id不能与该值重复。 (4)查看expire-log-day。binlog过期时间,默认为10天。你可以根据你硬盘空间大小及每天产生的数据量修改。如果你有冷备,则一般设成2-3天即可。 2、操作数据库 (1)在linux命令行下登录mysql mysql -uroot -p(你的root密码) (2)创建并授权一个帐号 mysql> GRANT REPLICATION SLAVE ON . TO 'slave_account'@'10.121.0.220' identified by '123456' 这句的意思是,允许从服务器'10.121.0.220 '使用'slave-account'及'123456'这个帐号密码对对主服务器的所有数据库(.)进行主从复制('REPLICATION SLAVE'). (3)重启mysql使上述配置生效 etc/init.d/mysql restart 或 service mysql restart (4)查看主服务器binlog状态 mysql> show master stauts; (图2) 记下File及Position下的值。以备在配置从服务器时使用。 注:File:当前binlog的文件名,每重启一次mysql,就会生成一个新binlog文件 Position:当前binlog的指针位置 三、从服务器配置 1、配置mysql.cnf vi /etc/my.cnf (1)修改server-id=2(该值不能与主服务器的server-id同。如果有多个从服务器,则该值顺延) (2)添加如下两行: relay-log-index=slave-relay-bin.index (中继日志的索引文件) relay-log=slave-relay-bin (中继日志的文件前缀) (3)重启mysql使上述配置生效 /etc/init.d/mysql restart (4)登录mysql mysql -uroot -p你的密码 (5)停止主从复制服务 mysql> stop slave (6)主从关联配置 mysql> change master to master_host='10.121.0.110', #主服务器IP master_user='slave_account ', #主服务器访问从服务器的用户,即上述第三条第2小条第2子条所述帐号 master_password='123456', #主服务器访问从的密码,即上述第三条第2小条第2子条所述密码 master_log_file='mysql-bin.000008', #主服务器起始的binlog文件名,即图2的file master_log_pos=107; #主服务器binlog起始位置,即图2的postion 上述每行都特别重要,错一个字符都不行 (7)启动从服务 mysql> start slave (8) 查看从服务的状态,判断从服务是否生效 mysql> show slave status\G; (G参数为纵向显示结果) 会显示如下结果 Slave_IO_State: Waiting for master to send event Master_Host: 192.168.0.110 Master_User: slave_account Master_Port: 3306 Connect_Retry: 60 Master_Log_File: mysql-bin.00008 Read_Master_Log_Pos: 107 Relay_Log_File: slave-relay-bin.000002 Relay_Log_Pos: 253 Relay_Master_Log_File: mysql-bin.00008 Slave_IO_Running: Yes Slave_SQL_Running: Yes Replicate_Do_DB: Replicate_Ignore_DB: Replicate_Do_Table: Replicate_Ignore_Table: Replicate_Wild_Do_Table: Replicate_Wild_Ignore_Table: Last_Errno: 0 Last_Error: Skip_Counter: 0 Exec_Master_Log_Pos: 264 Relay_Log_Space: 409 Until_Condition: None Until_Log_File: Until_Log_Pos: 0 Master_SSL_Allowed: No Master_SSL_CA_File: Master_SSL_CA_Path: Master_SSL_Cert: Master_SSL_Cipher: Master_SSL_Key: Seconds_Behind_Master: 0 Master_SSL_Verify_Server_Cert: No Last_IO_Errno: 0 Last_IO_Error: Last_SQL_Errno: 0 Last_SQL_Error: Replicate_Ignore_Server_Ids: Master_Server_Id: 1 如果Slave_IO_Running和Slave_SQL_Running都显示YES,则表示从与主的读写通讯正常、主动复制已经运行,则表明我们主从复制已经设置成功。如果出现故障,则看下节“故障排除”。 然后,你再在主服务器插入一条数据,看看从服务器相应数据库里有没有做相应更新。如果有,则大功告成。 **四、权限配置 ** 虽然某些mysql版本不进行如下操作,可能也能正常运行,但我还是强列建议你设置。否则,必有安全之虑。 1、为master分配select、insert、update、delete权限 mysql>GRANT SELECT,INSERT,UPDATE,DELETE ON . TO '数据库的帐号'@'WEB服务器的IP' identified by '密码'。 注意,虽然master只负责写,但也必须有select权限。原因是使用事务时,需要从master查询,二是update/delete这些命令都需要使用select权限。 2、为slave分配select权限 mysql> GRANT SELECT ON . TO '数据库的帐号'@'WEB服务器的IP' identified by '密码'; 这样设置也有一个弊端,就是当主宕机时,读写分离机制分主动将写操作转到从上来,这时,就会出现写不正常的情况。所以,slave要分配哪些权限,还看你自己选择。 五、防火墙配置 刚才我们为了调试方便,先关闭了防火墙,但这样做,非常很不安全。特别是数据库服务器,关系公司的身家性命,更不可小视。 主从复制的防火墙,还是比较好设置的,如果你只有一台web服务器,则只需要在主、从服务器的iptables里开放2个授权即可。先在主服务器执行如下命令: iptables INPUT -s 10.121.0.220 -j ACCEPT (允许从服务器访问) iptables INPUT -s 10.121.2.142 -j ACCEPT (允许web服务器访问) service iptables save (保存上述规则) service iptables restart (重启iptables) 在从中将第一条换成主的IP即可。 设置完后,再在从上用show slave status看看主从复制是否正常。 六、一些故障排除 设置过程中,可能会出现如下几个故障 (1) Slave_IO_Running: No (2) Slave_IO_Running: Connect (3)Last_IO_Error: error connecting to master 'slave-account@192.168.0.110:3306' - retry-time: 60 retries: 8640 其实上述故障,都是由IO不正常造成的,请从如下几个步骤着手检查。 a.配置完主或从的my.cnf后,是否重启了mysql服务。如果重启还不成功,则可以用reboot命令重启服务器后再试 b.change master那一步所填写的信息是否正确。 (4)Last_IO_Error: Fatal error: The slave I/O thread stops because master and slave have equal MySQL server ids; these ids must be different for replication to work (or the --replicate-same-server-id option must be used on slave but this does not always make sense; please check the manual before using it). 如上是说主、从使用了相同的server-id,进入my.cnf检查,改正之,然后重启mysql服务。 七、php设置 在php的数据库连接配置文件里作如下设置即可 //该行读写分离支持 'DB_DEPLOY_TYPE'=> 1, 'DB_RW_SEPARATE'=>true, //主、从数据库的IP地址,前为主,后从 'DB_HOST' => '10.121.0.110,10.121,0.220', // 数据库类型 'DB_TYPE' => 'mysql', // 用户名,如果主和从的用户名相同,则 可省略一个 'DB_USER' => 'root root', // 用户名,如果主和从密码相同,则可省略一个 'DB_PWD' => '123456 123456', // 用户名,如果主和从数据库相同,则可省略一个 'DB_NAME' => 'test test' 来源:http://mp.weixin.qq.com/s/CVKSGYgmgqCW2j44pITl1A
商城中通过订单号查询信息,但是订单号往往很长,以订单号(长的字段值)为where查询条件时候返回json数据,解决方法先把where条件写成数组。然后写在SQL语句中。 修改前的 $list = db('biao')->where('order_no',$order_no)->find(); 修改后的 $where['order_no'] = $order_no; $list = db('biao')->where($where)->find();
前端时间做一个百度地图,需要在地图上显示所有商家(每个商家都有一个自己的经纬度,从后台传到前台),但是百度地图API都是JS写的,下面是解决方法: 传过来的写个隐藏的标签先获取到这些数据 <div style="display: none"> {foreach name="lists" id="list"} <p class="longitude">{$list.longitude}</p> <p class="latitude"> {$list.latitude}</p> {/foreach} </div> // 添加标注 var longitude = $('.longitude'); $.each(longitude,function (index,ele) { var points = new BMap.Point($(ele).text(), $('.latitude:eq('+index+')').text()); addMarker(points); })