发布于 03月22, 2018

整理一些Node常见实用的插件工具

一、web特殊字体处理,字体压缩

1.推荐字蛛:通过分析本地 CSS 与 HTML 文件获取 WebFont 中没有使用的字符,并将这些字符数据从字体中删除以实现压缩,同时生成跨浏览器使用的格式。

  • 环境依赖:npm Mac 安装nodejs step 1(新手推荐): 访问nodejs官网,点击蓝色选框区域稳定版,并下载https://nodejs.org/en/

  • 字蛛安装: npm install font-spider -g

  • 在 CSS 中使用 WebFont:

    /*声明 WebFont*/
    @font-face {
    font-family: 'pinghei';
    src: url('../font/pinghei.eot');
    src:
      url('../font/pinghei.eot?#font-spider') format('embedded-opentype'),
      url('../font/pinghei.woff') format('woff'),
      url('../font/pinghei.ttf') format('truetype'),
      url('../font/pinghei.svg') format('svg');
    font-weight: normal;
    font-style: normal;
    }
    /*使用选择器指定字体*/
    .home h1, .demo > .test {
      font-family: 'pinghei';
    }
  1. @font-face 中的 src 定义的 .ttf 文件必须存在,其余的格式将由工具自动生成

  2. 开发阶段请使用相对路径的 CSS 与 WebFont

  • 运行 font-spider 命令:
font-spider ./demo/*.html

路径为本地html地址 页面依赖的字体将会自动压缩好,原 .ttf 字体会备份

阅读全文 »

发布于 05月17, 2017

整理不用系统各个版本apache多站点配置相关问题

一、Centos Apache 多站点配置

确认apache配置文件位置: /etc/httpd/conf/httpd.conf, 系统自动加载 "/etc/httpd/conf.d" 目录下面的 "*.conf"文件,可通过创建多个 ".conf" 文件来配置多站点,如下添加:

<virtualhost *:80="">
    ServerAdmin email@163.com    # 网站根目录
    DocumentRoot /opt/www/double-xu/trunk    # 网站域名 
    ServerName xxx.com    # 默认首页    DirectoryIndex index.html index.php    # 错误日志(注意logs文件夹必须存在,否则启动apache会失败)
    ErrorLog /opt/logs/error.log    # 访问日志
    CustomLog /opt/logs/customer common
</virtualhost>

「注意」:多个 “.conf” 文件中,前面必须加上一行 “NameVirtualHost *:80”,有且只有一行;也可以直接注释掉 “/etc/httpd/conf/httpd.conf” 这个文件中的 “NameVirtualHost *:80”即可

阅读全文 »

发布于 05月09, 2017

整理Mac OS使用过程中遇到的一些问题

1.Mac 目录或文件权限操作失败

对于Mac OS X 10.11 El Capitan + 的用户,由于系统启用了SIP(System Integrity Protection), 导致root用户(超管)也没有修改部分系统文件的权限,可以按如下方式恢复权限。

屏蔽方法:重启Mac,按住command+R,进入recovery模式。选择打开Utilities下的终端,输入:csrutil disable 回车,然后正常重启Mac即可。

具体可见:http://www.howtogeek.com/230424/how-to-disable-system-integrity-protection-on-a-mac-and-why-you-shouldnt/

阅读全文 »

发布于 03月23, 2017

整理Nginx配置SSL实现HTTPS的一些方式

*-----Let's Encrypt,免费好用的HTTPS证书----- *

HTTPS(全称:Hyper Text Transfer Protocol over Secure Socket Layer),是以安全为目标的HTTP通道,简单讲是HTTP的安全版。即HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL。

Let's Encrypt,是2016412日成立的一家证书授权中心,提供免费的传输层安全(TLS)X.509证书,通过自动化的过程消除目前安全网站证书需要手工创建,加密,签名,安装以及更新的复杂性。

根据acme-tiny提供的说明文档和我自己的实施过程列出以下几步:

克隆脚本

sudo git clone https://github.com/diafygi/acme-tiny.git  
cd acme-tiny

*创建Let's Encrypt私钥 *

openssl genrsa 4096 > account.key

创建CSR(Certificate Signing Request,证书签名请求) 文件

ACME协议 (Let's Encrypt所使用的) 需要一个csr文件,用来进行证书签名和证书更新。 将需要加密的域名加到下面的代码中,目前一张证书最多可以加密 100 个域名:

openssl genrsa 4096 > domain.key     
openssl req -new -sha256 -key domain.key -subj "/" -reqexts SAN -config <(cat /etc/ssl/openssl.cnf <(printf "[SAN]\nsubjectAltName=DNS:yoursite.com,DNS:www.yoursite.com")) > domain.csr

注意:openssl.cnf 文件的位置可能会因为linux版本的不同而有变 证明你拥有该域名

acme-tiny脚本会生成验证文件并写入到你指定的目录下,然后通过 ".well-known/acme-challenge/" 这个URL来访问到验证文件. 注意: Let's Encrypt 会对你的服务器做一次http请求来进行验证,因此你需要保证80端口能够访问.

手动生成challenges目录,用来存放验证文件(路径可以根据需要修改)

mkdir -p /var/www/challenges

#配置nignx的80端口

server {
    listen 80;
    server_name yoursite.com www.yoursite.com;
    if ( $request_uri !~ "/.well-known/acme-challenge/*" ) { # 让 Let's Encrypt 成功访问到验证文件不受 301 影响
        return 301 https://yoursite.com$request_uri; # 注意进行301重定向到https,否则通过http仍能访问你的站点
    }
    location /.well-known/acme-challenge/ {
        alias /var/www/challenges/;
        try_files $uri =404;
    }

    #...你的其他配置
}

注意:出现类似错误时 “ValueError: Wrote file to /data/***/domain.com/gtSQLC9ASFCUqNTce1Ak-cM_zfNdnFySvjdUnNAn3rI, but couldn't download http://domain.com/.well-known/acme-challenge/gtSQLC9ASFCUqNTce1Ak-cM_zfNdnFySvjdUnNAn3rI”,可借助301 让 Let's Encrypt 成功访问到验证文件

Apache 则需修改 .htaccess 文件:

RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

获取签名证书

sudo chmod +x acme_tiny.py  
python acme_tiny.py --account-key ./account.key --csr ./domain.csr --acme-dir /var/www/challenges/ > ./signed.crt

安装证书

针对nginx, 你还需要将 Let's Encrypt 的中间件证书 intermediate.pem 内容附加在签名证书signed.crt之后:

wget -O - https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem > intermediate.pem  
cat signed.crt intermediate.pem > chained.pem
server {
    listen 443;
    server_name yoursite.com www.yoursite.com;

    ssl on;
    ssl_certificate /path/to/chained.pem;
    ssl_certificate_key /path/to/domain.key;
    ssl_session_timeout 5m;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA;
    ssl_session_cache shared:SSL:50m;
    ssl_prefer_server_ciphers on;

    #...你的其他配置
}

证书自动更新定时任务 恭喜!你的网站已经使用上了HTTPS。 但Let's Encrypt 证书有效期只有90天, 所以需要定期更新。现在只需要写一个更新脚本并把它放到定时任务中即可。

脚本内容:

#!/usr/bin/sh
python /path/to/acme_tiny.py --account-key /path/to/account.key --csr /path/to/domain.csr --acme-dir /var/www/challenges/ > /tmp/signed.crt || exit
wget -O - https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem > intermediate.pem
cat /tmp/signed.crt intermediate.pem > /path/to/chained.pem
service nginx reload

定时任务可以设置为每个月执行一次:

0 0 1 * * sudo bash /path/to/renew_cert.sh 2>> /var/log/acme_tiny.log

转载地址:https://macken.me/article/encrypt-your-webiste-with-lets-encrypt

注释:--其他更新证书方式:--

第一,通过ssh连接上服务器,执行命令: “git clone https://github.com/letsencrypt/letsencrypt”,下载脚本文件到服务器。 第二,下载完成后,进入下载目录:cd letsencrypt; 第三,关闭nginx服务器:“service nginx stop”,防止端口占用; 第四,执行更新证书脚本:“./letsencrypt-auto certonly --standalone --email XXXX@qq.com -d XXX.XXX.com”,其中--email是设置的邮箱,用于接收消息,-d是设置的对应的域名目录,等看到消息中出现“IMPORTANT NOTES:- Congratulations! ”说明续期成功。 let's Encrypt 免费ssl证书快速续期 第五,开启nginx服务器,刷新网站,就会看到证书的过期日期已经更新。

阅读全文 »

发布于 03月17, 2017

整理一些不同环境下PHP扩展的安装问题

一、PHP中PDO_MYSQL扩展安装的2种方法

部署测试系统:ubuntu /centos6.0+(仅限Linux/Unix参考)

查看扩展支持是否安装:

php -i|grep PDO

显示如下:

PDO
PDO support => enabled
PDO drivers => mysql
PDO Driver for MySQL => enabled

方法1: 下载安装。首先是下载pdo_mysql扩展的源码包,http://pecl.php.net/package/PDO_MYSQL , 服务器端下载:

# wget http://pecl.php.net/get/PDO_MYSQL-1.0.2.tgz

然后是解压缩,

# tar -zxvf PDO_MYSQL-1.0.2.tgz

进入解压后的目录,然后执行phpize(PHP安装目录)。

# /usr/local/php/bin/phpize
Configuring for:
PHP Api Version: 20100412
Zend Module Api No: 20100525
Zend Extension Api No: 220100525

下面生成makefile。后面的两个参数必须要添加,一开始我没有添加,结果分别都提示找不到php-config和mysql的header文件。

# ./configure –with-php-config=/usr/local/php/bin/php-configwith-pdo-mysql=/usr/local/mysql

参数说明:

--with-php-config=/usr/local/php/bin/php-config 指定安装PHP的时候的配置
--with-pdo-MySQL=/usr/local/mysql/ 指定MySQL数据库的安装目录位置

在make之前做一个mysql的header文件的软连接。因为mysql安装的时候指定了目录,不做软连接的话,还是找不到header文件。

# ln -s /usr/local/mysql/include/* /usr/local/include/

[注]:ubuntu mysql判断自己的库和头文件的位置,如下命令

mysql_config --cflags --libs

~~~

然后make和make install。

# make
# make install

之后会提示如下,意思是扩展被安装到了如下目录里。

Installing shared extensions:     /usr/local/php/lib/php/extensions/no-debug-zts-20100525/

当前系统环境PHP扩展统一在extensions目录下,所以把生成的so放入该目录下:

# mv /usr/local/php/lib/php/extensions/no-debug-zts-20100525/pdo_mysql.so /usr/local/php/lib/php/extensions/

然后修改php.ini文件

找到; extension_dir = “./”这一行,去掉注释,并修改路径。

extension_dir = “/usr/local/php/lib/php/extensions/”

找到; extension=php_pdo_mysql.dll这一行,去掉注释,并修改后面的文件名。

extension=pdo_mysql.so

此处注意扩展文件名,去掉前缀php_,否则找不到文件。后面的dll是windows下的文件名,这里改成so。

最后重启apache/nginx,用phpinfo()查看是否生效。

阅读全文 »

发布于 03月01, 2017

整理一些阿里云ECS服务器运维相关问题

一、导致Mysql死掉的情况:

示例1:

[root@centos var]# service mysqld restart
mysql server pid file could not be found……    [FAILED]

服务器症状: web网站504 time out~ 可ping通,检查无丢包现象;尝试重启mysql数据库,操作失败,!!磁盘满!!用df命令查了下,果然磁盘满了,因为当时分区采用系统默认,不知道为什么不能自动扩容!

检测显示:

[root@test ~]# df
文件系统   1K-块      已用              可用        已用%     挂载点
/dev1/     51606140  47734848   1249852  100%        /***

解决:磁盘扩容

阅读全文 »

发布于 02月08, 2017

谷歌 - Progressive Web App介绍

Progressive Web Apps 是结合了 web 和 原生应用中最好功能的一种体验。对于首次访问的用户它是非常有利的, 用户可以直接在浏览器中进行访问,不需要安装应用。随着时间的推移当用户渐渐地和应用建立了联系,它将变得越来越强大。它能够快速地加载,即使在比较糟糕的网络环境下,能够推送相关消息, 也可以像原生应用那样添加至主屏,能够有全屏浏览的体验。

什么是 Progressive Web App?

Progressive Web Apps 是:

  • 渐进增强 - 能够让每一位用户使用,无论用户使用什么浏览器,因为它是始终以渐进增强为原则无序列表项0
  • ** 响应式用户界面** - 适应任何环境:桌面电脑,智能手机,笔记本电脑,或者其他设备。
  • 不依赖网络连接 - 通过 service workers 可以在离线或者网速极差的环境下工作。
  • 类原生应用 - 有像原生应用般的交互和导航给用户原生应用般的体验,因为它是建立在 app shell model 上的。
  • 持续更新 - 受益于 service worker 的更新进程,应用能够始终保持更新。
  • 安全 - 通过 HTTPS 来提供服务来防止网络窥探,保证内容不被篡改。
  • 可发现 - 得益于 W3C manifests 元数据和 service worker 的登记,让搜索引擎能够找到 web 应用。
  • *再次访问 *- 通过消息推送等特性让用户再次访问变得容易。
  • 可安装 - 允许用户保留对他们有用的应用在主屏幕上,不需要通过应用商店。
  • 可连接性 - 通过 URL 可以轻松分享应用,不用复杂的安装即可运行。

这引导指南将会引导你完成你自己的 Progressive Web App,包括设计时需要考虑的因素,也包括实现细节,以确保你的应用程序符合 Progressive Web App 的关键原则。

我们将要做什么?

你将会学到

  • 如何使用 "app shell" 的方法来设计和构建应用程序。
  • 如何让你的应用程序能够离线工作。
  • 如何存储数据以在离线时使用。

你需要

  • 标题Chrome 52 或以上
  • Web Server for Chrome 或其他的网络服务器。
  • 示例代码
  • 代码编辑器
  • HTML,CSS 和 JavaScript 的基本知识

这份引导指南的重点是 Progressive Web Apps。其中有些概念的只是简单的解释 而有些则是只提供示例代码(例如 CSS 和其他不相关的 Javascipt ),你只需复制和粘贴即可。

设置

下载示例代码

你可以下载本 progressive web app 引导指南需要的所有代码

将下载好的zip文件进行解压缩。这将会解压缩一个名为(your-first-pwapp-master)的根文件夹。这文件夹包含了这指南你所需要的资源。

名为 step-NN 的文件夹则包含了这指南每个步骤的完整的代码。你可以把他当成参考。

安装及校验网络服务器

你可以选择其他的网络服务器,但在这个指南我们将会使用Web Server for Chrome。如果你还没有安装,你可以到 Chrome 网上应用店下载。

安装完毕后,从书签栏中选择Apps的捷径:

alt

接下来点击Web Server的图标

alt

你将会看到以下的窗口,这让你配置你的本地网络服务器:

alt

点击 choose folder 的按钮,然后选择名为 work 的文件夹。这会把目录和文件都以HTTP的方式展示出来。URL地址可以在窗口里的 *Web Server URL(s) *找到。

在选项中,选择"Automatically show index.html" 的选择框:

alt

然后在 "Web Server: STARTED" 的按钮拉去左边,在拉去右边,以将本地网络服务器关闭并重启。

alt

现在你可以使用游览器来访问那个文件夹(点击窗口内的Web Server URL下的链接即可)。你将会看到以下的画面:

alt

很明显的,这个应用程序并没有什么功能。现在只有一个加载图标在那里转动,这只是来确保你的网络服务器能正常操作。在接下来的步骤,我们将会添加更多东西。

基于应用外壳的架构

** 什么是应用外壳(App Shell)**

App Shell是应用的用户界面所需的最基本的 HTML、CSS 和 JavaScript,也是一个用来确保应用有好多性能的组件。它的首次加载将会非常快,加载后立刻被缓存下来。这意味着应用的外壳不需要每次使用时都被下载,而是只加载需要的数据。

应用外壳的结构分为应用的核心基础组件和承载数据的 UI。所有的 UI 和基础组件都使用一个 service worker 缓存在本地,因此在后续的加载中 Progressive Web App 仅需要加载需要的数据,而不是加载所有的内容。

alt

换句话说,应用的壳相当于那些发布到应用商店的原生应用中打包的代码。它是让你的应用能够运行的核心组件,只是没有包含数据。

为什么使用基于应用外壳的结构?

使用基于应用外壳的结构允许你专注于速度,给你的 Progressive Web App 和原生应用相似的属性:快速的加载和灵活的更新,所有这些都不需要用到应用商店。

设计应用外壳

第一步是设计核心组件

问问自己:

  • 需要立刻显示什么在屏幕上?
  • 我们的应用需要那些关键的 UI 组件?
  • 应用外壳需要那些资源?比如图片,JavaScript,样式表等等。

我们将要创建一个天气应用作为我们的第一个 Progressive Web App 。它的核心组件包括:

在设计一个更加复杂的应用时,内容不需要在首次全部加载,可以在之后按需加载,然后缓存下来供下次使用。比如,我们能够延迟加载添加城市的对话框,直到完成对首屏的渲染且有一些空闲的时间。

实现应用外壳

任何项目都可以有多种起步方式,通常我们推荐使用 Web Starter Kit。但是,这里为了保持我们的项目 足够简单并专注于 Progressive Web Apps,我们提供了你所需的全部资源。

为应用外壳编写 HTML 代码

为了保证我们的起步代码尽可能清晰,我们将会开始于一个新的 index.html 文件并添加在 构建应用外壳中谈论过的核心组件的代码

请记住,核心组件包括:

  • 包含标题的头部,以及头部的 添加/刷新 按钮
  • 放置天气预报卡片的容器
  • 天气预报卡片的模板
  • 一个用来添加城市的对话框
  • 一个加载指示器
<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Weather PWA</title>
    <link rel="stylesheet" type="text/css" href="styles/inline.css">
</head>

<body>
    <header class="header">
        <h1 class="header__title">Weather PWA</h1>
        <button id="butRefresh" class="headerButton"></button>
        <button id="butAdd" class="headerButton"></button>
    </header>
    <main class="main">
        <div class="card cardTemplate weather-forecast" hidden>
            . . .
        </div>
    </main>
    <div class="dialog-container">
        . . .
    </div>
    <div class="loader">
        <svg viewBox="0 0 32 32" width="32" height="32">
            <circle id="spinner" cx="16" cy="16" r="14" fill="none"></circle>
        </svg>
    </div>
    <!-- Insert link to app.js here -->
</body>

</html>

需要注意的是,在默认情况下加载指示器是显示出来的。这是为了保证 用户能在页面加载后立刻看到加载器,给用户一个清晰的指示,表明页面正在加载。

为了节省你的时间,我们已经已创建了 stylesheet。

添加关键的 JavaScript 启动代码

现在我们的 UI 已经准备好了,是时候来添加一些代码让它工作起来了。像搭建应用外壳的时候那样,注意 考虑哪些代码是为了保持用户体验必须提供的,哪些可以延后加载。

在启动代码中,我们将包括(你可以在(scripts/app.js)的文件夹中找到):

一个 app 对象包含一些和应用效果的关键信息。 为头部的按钮(add/refresh)和添加城市的对话框中的按钮(add/cancel)添加事件监听 函数。 一个添加或者更新天气预报卡片的方法(app.updateForecastCard)。 一个从 Firebase 公开的天气 API 上获取数据的方法(app.getForecast)。 一个迭代当前所有卡片并调用 app.getForecast 获取最新天气预报数据的方法 (app.updateForecasts). 一些假数据 (fakeForecast) 让你能够快速地测试渲染效果。

测试

现在,你已经添加了核心的 HTML、CSS 和 JavaScript,是时候测试一下应用了。这个时候它能做的可能还不多,但要确保在控制台没有报错信息。

为了看看假的天气信息的渲染效果,从 index.html中取消注释以下的代码:

<!--<script src="scripts/app.js" async></script>-->

接下来,从 app.js中取消注释以下的代码:

// app.updateForecastCard(initialWeatherForecast);

刷新你的应用程序,你将会看到一个比较整齐漂亮的天气预报的卡片:

alt

尝试并确保他能正常运作之后,将 app.updateForecastCard 清除。

从快速的首次加载开始

Progressive Web Apps 应该能够快速启动并且立即可用。目前,我们的天气应用能够快速启动,但是还不能使用,因为还没有数据。我们能够发起一个 AJAX 请求来获取数据,但是额外的请求会让初次加载时间变长。取而代之的方法是,在初次加载时提供真实的数据。

插入天气预报信息

在本实例中,我们将会静态地插入天气预报信息,但是在一个投入生产环境的应用中,最新的天气预报数据会由服务器根据用户的 IP 位置信息插入。

这代码已经包括了所需的资料,那就是我们在前个步骤所用的 initialWeatherForecast。

区分首次运行

但我们如何知道什么时候该展示这些信息,那些数据需要存入缓存供下次使用?当用户下次使用的时候,他们所在城市可能已经发生了变动,所以我们需要加载目前所在城市的信息,而不是之前的城市。

用户首选项(比如用户订阅的城市列表),这类数据应该使用 IndexedDB 或者其他快速的存储方式存放在本地。 为了尽可能简化,这里我们使用 localStorage 进行存储,在生产环境下这并不是理想的选择,因为它是阻塞型同步的存储机制,在某些设备上可能很缓慢。

首先,让我们添加用来存储用户首选项的代码。从代码中寻找以下的TODO注解:

// TODO add saveSelectedCities function here

然后将以下的代码粘贴在TODO注解的下一行。

//  将城市裂变存入 localStorage.
app.saveSelectedCities = function() {
    var selectedCities = JSON.stringify(app.selectedCities);
    localStorage.selectedCities = selectedCities;
};

接下来,添加一些启动代码来检查用户是否已经订阅了某些城市,并渲染它们,或者使用插入的天气数据来渲染。从代码中寻找以下的TODO注解:

// TODO add startup code here

然后将以下的代码粘贴在TODO注解的下一行。

/****************************************************************************   
 *
 * 用来启动应用的代码
 *
 * 注意: 为了简化入门指南, 我们使用了 localStorage。
 *   localStorage 是一个同步的 API,有严重的性能问题。它不应该被用于生产环节的应用中!
 *   应该考虑使用, IDB (https://www.npmjs.com/package/idb) 或者
 *   SimpleDB (https://gist.github.com/inexorabletash/c8069c042b734519680c)
 *
 ****************************************************************************/

app.selectedCities = localStorage.selectedCities;
if (app.selectedCities) {
  app.selectedCities = JSON.parse(app.selectedCities);
  app.selectedCities.forEach(function(city) {
    app.getForecast(city.key, city.label);
  });
} else {
  app.updateForecastCard(initialWeatherForecast);
  app.selectedCities = [
    {key: initialWeatherForecast.key, label: initialWeatherForecast.label}
  ];
  app.saveSelectedCities();
}

储存已被选择的城市

现在,你需要修改"add city"按钮的功能。这将会把已被选择的城市储存进local storage。

更新butAddCity中的代码:

document.getElementById('butAddCity').addEventListener('click', function() {
    // Add the newly selected city
    var select = document.getElementById('selectCityToAdd');
    var selected = select.options[select.selectedIndex];
    var key = selected.value;
    var label = selected.textContent;
    if (!app.selectedCities) {
      app.selectedCities = [];
    }
    app.getForecast(key, label);
    app.selectedCities.push({key: key, label: label});
    app.saveSelectedCities();
    app.toggleAddDialog(false);
  });

测试

  • 在首次允许时,你的应用应该立刻向用户展示 initialWeatherForecast 中的天气数据。
  • 添加一个新城市确保会展示两个卡片。
  • 刷新浏览器并验证应用是否加载了天气预报并展示了最新的信息。

使用 Service Workers 来预缓存应用外壳

Progressive Web Apps 是快速且可安装的,这意味着它能在在线、离线、断断续续或者缓慢的网络环境下使用。为了实现这个目标,我们需要使用一个 service worker 来缓存应用外壳,以保证它能始终迅速可用且可靠。

如果你对 service workers 不熟悉,你可以通过阅读 介绍 Service Workers 来了解关于它能做什么,它的生命周期是如何工作的等等知识。

service workers 提供的是一种应该被理解为渐进增强的特性,这些特性仅仅作用于支持service workers 的浏览器。比如,使用 service workers 你可以缓存应用外壳和你的应用所需的数据,所以这些数据在离线的环境下依然可以获得。如果浏览器不支持 service workers ,支持离线的 代码没有工作,用户也能得到一个基本的用户体验。使用特性检测来渐渐增强有一些小的开销,它不会在老旧的不支持 service workers 的浏览器中产生破坏性影响。

注册 service worker

为了让应用离线工作,要做的第一件事是注册一个 service worker,一段允许在后台运行的脚本,不需要 用户打开 web 页面,也不需要其他交互。

这只需要简单两步:

创建一个 JavaScript 文件作为 service worker 告诉浏览器注册这个 JavaScript 文件为 service worker 第一步,在你的应用根目录下创建一个空文件叫做 service-worker.js 。这个 service-worker.js 文件必须放在跟目录,因为 service workers 的作用范围是根据其在目录结构中的位置决定的。

接下来,我们需要检查浏览器是否支持 service workers,如果支持,就注册 service worker,将下面代码添加至 app.js中。

if('serviceWorker' in navigator) {  
    navigator.serviceWorker  
        .register('/service-worker.js')  
        .then(function() { console.log('Service Worker Registered'); });  
}

缓存站点的资源

当 service worker 被注册以后,当用户首次访问页面的时候一个 install 事件会被触发。在这个事件的回调函数中,我们能够缓存所有的应用需要再次用到的资源。

当 service worker 被激活后,它应该打开缓存对象并将应用外壳需要的资源存储进去。将下面这些代码加入你的 service-worker.js (你可以在your-first-pwapp-master/work中找到) :

var cacheName = 'weatherPWA-step-6-1';
var filesToCache = [];

self.addEventListener('install', function(e) {
  console.log('[ServiceWorker] Install');
  e.waitUntil(
    caches.open(cacheName).then(function(cache) {
      console.log('[ServiceWorker] Caching app shell');
      return cache.addAll(filesToCache);
    })
  );
});

首先,我们需要提供一个缓存的名字并利用 caches.open()打开 cache 对象。提供的缓存名允许我们给 缓存的文件添加版本,或者将数据分开,以至于我们能够轻松地升级数据而不影响其他的缓存。

一旦缓存被打开,我们可以调用 cache.addAll() 并传入一个 url 列表,然后加载这些资源并将响应添加至缓存。不幸的是 cache.addAll() 是原子操作,如果某个文件缓存失败了,那么整个缓存就会失败!

好的。让我们开始熟悉如何使用DevTools并学习如何使用DevTools来调试service workers。在刷新你的网页前,开启DevTools,从 Application 的面板中打开 Service Worker 的窗格。它应该是这样的:

alt

当你看到这样的空白页,这意味着当前打开的页面没有已经被注册的Service Worker。

现在,重新加载页面。Service Worker的窗格应该是这样的:

alt

当你看到这样的信息,这意味着页面有个Service Worker正在运行。

现在让我们来示范你在使用Service Worker时可能会遇到的问题。为了演示, 我们将把service-worker.js里的install 的事件监听器的下面添加在activate 的事件监听器。

self.addEventListener('activate', function(e) {
  console.log('[ServiceWorker] Activate');
});

当 service worker 开始启动时,这将会发射activate事件。

打开DevTools并刷新网页,切换到应用程序面板的Service Worker窗格,在已被激活的Service Worker中单击inspect。理论上,控制台将会出现[ServiceWorker] Activate的信息,但这并没有发生。现在回去Service Worker窗格,你会发现到新的Service Worker是在“等待”状态。

alt

简单来说,旧的Service Worker将会继续控制该网页直到标签被关闭。因此,你可以关闭再重新打开该网页或者点击 skipWaiting 的按钮,但一个长期的解决方案是在DevTools中的Service Worker窗格启用 Update on Reload 。当那个复选框被选择后,当每次页面重新加载,Service Worker将会强制更新

启用 update on reload 复选框并重新加载页面以确认新的Service Worker被激活。

Note: 您可能会在应用程序面板里的Service Worker窗格中看到类似于下面的错误信息,但你可以放心的忽略那个错误信息。

alt

Ok, 现在让我们来完成activate 的事件处理函数的代码以更新缓存。

self.addEventListener('activate', function(e) {  
  console.log('[ServiceWorker] Activate');  
  e.waitUntil(  
    caches.keys().then(function(keyList) {  
      return Promise.all(keyList.map(function(key) {  
        console.log('[ServiceWorker] Removing old cache', key);  
        if (key !== cacheName) {  
          return caches.delete(key);  
        }  
      }));  
    })  
  );  
});

确保在每次修改了 service worker 后修改 cacheName,这能确保你永远能够从缓存中获得到最新版本的文件。过一段时间清理一下缓存删除掉没用的数据也是很重要的。

最后,让我们更新一下 app shell 需要的缓存的文件列表。在这个数组中,我们需要包括所有我们的应用需要的文件,其中包括图片、JavaScript以及样式表等等。

var filesToCache = [  
  '/',  
  '/index.html',  
  '/scripts/app.js',  
  '/styles/inline.css',  
  '/images/clear.png',  
  '/images/cloudy-scattered-showers.png',  
  '/images/cloudy.png',  
  '/images/fog.png',  
  '/images/ic_add_white_24px.svg',  
  '/images/ic_refresh_white_24px.svg',  
  '/images/partly-cloudy.png',  
  '/images/rain.png',  
  '/images/scattered-showers.png',  
  '/images/sleet.png',  
  '/images/snow.png',  
  '/images/thunderstorm.png',  
  '/images/wind.png'  
];

我么的应用目前还不能离线工作。我们缓存了 app shell 的组件,但是我们仍然需要从本地缓存中加载它们。

从缓存中加载 app sheel

Service workers 可以截获 Progressive Web App 发起的请求并从缓存中返回响应。这意味着我们能够 决定如何来处理这些请求,以及决定哪些网络响应能够成为我们的缓存。

比如:

self.addEventListener('fetch', function(event) {  
  // Do something interesting with the fetch here  
});

让我们来从缓存中加载 app shell。将下面代码加入 service-worker.js 中:

self.addEventListener('fetch', function(e) {  
  console.log('[ServiceWorker] Fetch', e.request.url);  
  e.respondWith(  
    caches.match(e.request).then(function(response) {  
      return response || fetch(e.request);  
    })  
  );  
});

从内至外,caches.match() 从网络请求触发的 fetch 事件中得到请求内容,并判断请求的资源是 否存在于缓存中。然后以缓存中的内容作为响应,或者使用 fetch 函数来加载资源(如果缓存中没有该资源)。 response 最后通过 e.respondWith() 返回给 web 页面。

测试

你的应用程序现在可以在离线下使用了! 让我们来试试吧!

先刷新那个网页, 然后去DevTools里的 *Cache Storage *窗格中的 Application 面板上。展开该部分,你应该会在左边看到您的app shell缓存的名称。当你点击你的appshell缓存,你将会看到所有已经被缓存的资源。

alt

现在,让我们测试离线模式。回去DevTools中的 Service Worker *窗格,启用 *Offline 的复选框。启用之后,你将会在 Network 窗格的旁边看到一个黄色的警告图标。这表示您处于离线状态。

alt

刷新网页,然后你会发现你的网页仍然可以正常操作!

alt

下一步骤是修改该应用程序和service worker的逻辑,让气象数据能够被缓存,并能在应用程序处于离线状态,将最新的缓存数据显示出来。

Tip: 如果你要清除所有保存的数据(localStoarge,IndexedDB的数据,缓存文件),并删除任何的service worker,你可以在DevTools中的Application 面板里的Clear storage清除。

当心边缘问题

之前提到过,这段代码 一定不要用在生产环境下 ,因为有很多没有处理的边界情况。

缓存依赖于每次修改内容后更新缓存名称

比如缓存方法需要你在每次改变内容后更新缓存的名字。否则,缓存不会被更新,旧的内容会一直被缓存返回。 所以,请确保每次修改你的项目后更新缓存名称。

每次修改后所有资源都需要被重新下载

另一个缺点是当一个文件被修改后,整个缓存都需要被重新下载。这意味着即使你修改了一个简单的拼写错误 也会让整个缓存重新下载。这不太高效。

浏览器的缓存可能阻碍 service worker 的缓存的更新

另外一个重要的警告。首次安装时请求的资源是直接经由 HTTPS 的,这个时候浏览器不会返回缓存的资源, 除此之外,浏览器可能返回旧的缓存资源,这导致 service worker 的缓存不会得到 更新。

在生产环境中当下 cache-first 策略

我们的应用使用了优先缓存的策略,这导致所有后续请求都会从缓存中返回而不询问网络。优先缓存的策略是 很容易实现的,但也会为未来带来诸多挑战。一旦主页和注册的 service worker 被缓存下来,将会很难 去修改 service worker 的配置(因为配置依赖于它的位置),你会发现你部署的站点很难被升级。

我该如何避免这些边缘问题

我们该如何避免这些边缘问题呢? 使用一个库,比如 sw-precache, 它对资源何时过期提供了 精细的控制,能够确保请求直接经由网络,并且帮你处理了所有棘手的问题。

实时测试 service workers 提示

调试 service workers 是一件有调整性的事情,当涉及到缓存后,当你期望缓存更新,但实际上它并没有的时候,事情更是变得像一场恶梦。在 service worker 典型的生命周期和你的代码之间,你很快就会受挫。但幸运的是,这里有一些工具可以让你的生活更加简单。

其他的提示:

  • 一旦 service worker 被注销(unregistered)。它会继续作用直到浏览器关闭。
  • 如果你的应用打开了多个窗口,新的 service worker 不会工作,直到所有的窗口都进行了刷新,使用了 新的 service worker。
  • 注销一个 service worker 不会清空缓存,所以如果缓存名没有修改,你可能继续获得到旧的数据。
  • 如果一个 service worker 已经存在,而且另外一个新的 service worker 已经注册了,这个新的 service worker 不会接管控制权,知道该页面重新刷新后,除非你使用立刻控制的方式。

使用 Service Workers 来缓存应用数据

选择一个正确的缓存策略是很重要的,并且这取决于你应用中使用的数据的类型。比如像天气信息、股票信息等对实时性要求较高的数据,应该时常被刷新,但是用户的头像或者文字内容应该以较低的频率进行更新。

先使用缓存后使用请求结果 的策略对于我们的应用是非常理想的选择。应用从缓存中获取数据,并立刻显示在屏幕上,然后在网络请求返回后再更新页面。如果使用 先请求网络后缓存 的策略,用户可能不会等到数据从网络上加载回来便离开了应用。

先使用缓存后使用请求结果 意味着我们需要发起两个异步的请求,一个从请求缓存,另一个请求网络。我们应用中的网络请求不需要进行修改,但我们需要修改一下 service worker 的代码来缓存网络请求的响应并返回响应内容。

通常情况下,应该立刻返回缓存的数据,提供应用能够使用的最新信息。然后当网络请求返回后应用应该使用最新加载的数据来更新。

截获网络请求并缓存响应结果

我么需要修改 service worker 来截获对天气 API 的请求,然后缓存请求的结果,以便于以后使用。先使用缓存后使用请求结果 的策略中,我们希望请求的响应是真实的数据源,并始终提供给我们最新的数据。如果它不能做到,那也没什么,因为我们已经从缓存中给应用提供了最新的数据。

在 service worker 中,我们添加一个 dataCacheName 变量,以至于我们能够将应用数据和应用外壳资源分开。当应用外壳更新了,应用外壳的缓存就没用了,但是应用的数据不会受影响,并时刻保持能用。记住,如果将来你的数据格式改变了,你需要一种能够让应用外壳和应用数据能后保持同步的方法。

将下面代码添加至你的 service-worker.js 中:

var dataCacheName = 'weatherData-v1';

接下来,我么需要更新activate事件的回调函数,以它清理应用程序的外壳(app shell)缓存,并不会删除数据缓存。

if (key !== cacheName && key !== dataCacheName) {

最后,我么需要修改 fetch 事件的回调函数,添加一些代码来将请求数据 API 的请求和其他请求区分开来。

self.addEventListener('fetch', function(e) {  
  console.log('[ServiceWorker] Fetch', e.request.url);  
  var dataUrl = 'https://publicdata-weather.firebaseio.com/';  
  if (e.request.url.indexOf(dataUrl) === 0) {  
    // Put data handler code here  
  } else {  
    e.respondWith(  
      caches.match(e.request).then(function(response) {  
        return response || fetch(e.request);  
      })  
    );  
  }  
});

这段代码对请求进行拦截,判断请求的 URL 的开头是否为该天气 API,如果是,我们使用 fetch 来发起请求。一旦有响应返回,我们的代码就打开缓存并将响应存入缓存,然后将响应返回给原请求。

接下来,使用下面代码替换 // Put data handler code here

e.respondWith(  
  fetch(e.request)  
    .then(function(response) {  
      return caches.open(dataCacheName).then(function(cache) {  
        cache.put(e.request.url, response.clone());  
        console.log('[ServiceWorker] Fetched&Cached Data');  
        return response;  
      });  
    })  
);

我们的应用目前还不能离线工作。我们已经实现了从缓存中返回应用外壳,但即使我们缓存了数据,依旧需要依赖网络。

发起请求

之前提到过,应用需要发起两个异步请求,一个从请求缓存,另一个请求网络。应用需要使用 window 上的 caches 对象,并从中取到最新的数据。这是一个关于渐进增强 极佳 的例子,因为 caches 对象可能并不是在任何浏览器上都存在的,且就算它不存在,网络请求依旧能够工作,只是没有使用缓存而已。

为了实现该功能,我们需要:

  • 1.检查 cahces 对象是否存在在全局 window 对象上。
  • 2.向缓存发起请求
  • 3.如果向服务器发起的请求还没有返回结果,使用缓存中返回的数据更新应用。
  • 4.向服务器发起请求
  • 5.保存响应结果便于在之后使用
  • 6.使用从服务器上返回的最新数据更新应用

从缓存中获取资料

接下来,我们需要检查 caches 对象是否存在,若存在,就向它请求最新的数据。将下面这段代码添加至 app.getForecast() 方法中。

if ('caches' in window) {
  /*
   * Check if the service worker has already cached this city's weather
   * data. If the service worker has the data, then display the cached
   * data while the app fetches the latest data.
   */
  caches.match(url).then(function(response) {
    if (response) {
      response.json().then(function updateFromCache(json) {
        var results = json.query.results;
        results.key = key;
        results.label = label;
        results.created = json.query.created;
        app.updateForecastCard(results);
      });
    }
  });
}

我们的天气应用现在发起了两个异步请求,一个从缓存中,另一个经由 XHR。如果有数据存在于缓存中,它将会很快地(几十毫秒)被返回并更新显示天气的卡片,通常这个时候 XHR 的请求还没有返回来。之后当 XHR 的请求响应了以后,显示天气的卡片将会使用直接从天气 API 中请求的最新数据来更新。

如果因为某些原因,XHR 的响应快于 cache 的响应,hasRequestPending 标志位会阻止缓存中数据覆盖从网路上请求的数据。

var cardLastUpdatedElem = card.querySelector('.card-last-updated');
var cardLastUpdated = cardLastUpdatedElem.textContent;
if (cardLastUpdated) {
  cardLastUpdated = new Date(cardLastUpdated);
  // Bail if the card has more recent data then the data
  if (dataLastUpdated.getTime() < cardLastUpdated.getTime()) {
    return;
  }
}

亲自尝试

现在应用应该能够离线工作了。尝试关闭里本地启动的服务器,并切断网络,然后刷新页面。

然后去DevTools的 Application 面板上的 *Cache Storage *窗格。 展开该部分,你应该会在左边看到您的app shell缓存的名称。当你点击你的appshell缓存,你将会看到所有已经被缓存的资源。 alt

支持集成入原生应用

没有人喜欢在手机的键盘上输入一长串的 URL,有了添加至主屏幕的功能,你的用户可以选择添加一个图标在他们的屏幕上,就像从应用商店安装一个原生应用那样。而且这儿添加一个图标是更加容易的。

Web 应用安装横幅和添加至主屏

web 应用安装横幅给你能够让用户快速地将 web 应用添加至他们的主屏的能力,让他们能够很容易地再次进入你的应用。添加应用安装横幅是很简单的,Chrome 处理了几乎所有事情,我么只需要简单地包含一个应用程序清单(manifest)来说明你的应用的一些细节。

Chrome 使用了一系列标准包括对 service worker 的使用,加密连接状态以及用户的访问频率决定了什么时候展示这个横幅。除此之外,用户可以手动地通过 Chrome 中 “添加至主屏” 这个菜单按钮来添加。

使用 manifest.json 文件来声明一个应用程序清单

web 应用程序清单是一个简单的 JSON 文件,它给你了控制你的应用如何出现在用户期待出现的地方(比如用户手机主屏幕),这直接影响到用户能启动什么,以及更重要的,用户如何启动它。

使用 web 应用程序清单,你的应用可以:

  • 能够真实存在于用户主屏幕上
  • 在 Android 上能够全屏启动,不显示地址栏
  • 控制屏幕方向已获得最佳效果
  • 定义启动画面,为你的站点定义主题
  • 追踪你的应用是从主屏幕还是 URL 启动的
    {
    "name": "Weather",
    "short_name": "Weather",
    "icons": [{
      "src": "images/icons/icon-128x128.png",
        "sizes": "128x128",
        "type": "image/png"
      }, {
        "src": "images/icons/icon-144x144.png",
        "sizes": "144x144",
        "type": "image/png"
      }, {
        "src": "images/icons/icon-152x152.png",
        "sizes": "152x152",
        "type": "image/png"
      }, {
        "src": "images/icons/icon-192x192.png",
        "sizes": "192x192",
        "type": "image/png"
      }, {
        "src": "images/icons/icon-256x256.png",
        "sizes": "256x256",
        "type": "image/png"
      }],
    "start_url": "/index.html",
    "display": "standalone",
    "background_color": "#3E4EB8",
    "theme_color": "#2F3BA2"
    }
    追踪你的应用是从哪儿启动的最简单方式是在 start_url 参数后面添加一个查询字符串,然后使用工具来分析查询字段。如果你使用这个方法,记得要更新应用外壳缓存的文件,确保含有查询字段的文件被缓存。

告诉浏览器你的程序清单文件

将这段代码添加至你的 index.html 的 部分:

<link rel="manifest" href="/manifest.json">

最佳实践

  • 将程序清单的链接添加至你站点的所有页面上,这样在用户第一次访问的时候它能够被 Chrome 正确检索到,且不管用户从哪个页面访问的。
  • 如果同时提供了 name 和 short_name,short_name 是 Chrome 的首选。 为不同分辨率的屏幕提供不同的 icon。Chrome 会尝试使用最接近 48dp 的图标,比如在 2x 屏上使用 96px 的,在 3x屏上使用 144px 的。
  • 记得要包含一个适合在启动画面上显示的图标,另外别忘了设置 background_color。

扩展阅读:使用应用安装横幅

iOS Safari 的添加至主屏幕元素

在 index.html 中,将下面代码添加至 中:

<!-- Add to home screen for Safari on iOS -->
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="apple-mobile-web-app-title" content="Weather PWA">
<link rel="apple-touch-icon" href="images/icons/icon-152x152.png">

Windows 上的贴片图标

在 index.html 中,将下面代码添加至 中:

<meta name="msapplication-TileImage" content="images/icons/icon-144x144.png">
<meta name="msapplication-TileColor" content="#2F3BA2">

亲自尝试

尝试将应用在你的 Android Chrome 上添加至首屏,并确认启动画面上使用了正确的图标。 检查一下 Safari 和 Internet Explorer 确认图标正确地出现了。

部署在安全的主机上

最后一步是将我们的天气应用部署在一个支撑 HTTPs 的服务器上。如果你目前还没有一个这样的主机,那么最简单(且免费)的方法绝对是使用我们的静态资源部署服务 Firebase。它非常容易使用,通过 HTTPs 来提供服务且在全球 CDN 中。

可优化的地方:压缩并内联 CSS 样式

还有一些你需要考虑的事情,压缩关键的 CSS 样式并将其内联在 index.html 中。Page Speed Insights 建议以上内容要在 15k 以内。

看看当所有内容都内联后,首次加载资源有多大。

扩展阅读: PageSpeed Insight Rules

部署到 Firebase

如果你首次使用 Firebase,那么你需要使用你的 Google 账号登录 Firebase 并安装一些工具。

1.使用你的 Google 账号登录 Firebase https://firebase.google.com/

2.通过 npm 安装 Firebase 工具 :

npm install -g firebase-tools

你的账号被创建且已经登录后,你就可以开始部署了!

1.创建一个新的应用,在这儿:https://console.firebase.google.com/ 2.如果你最近没有登录过 Firebase 工具,请更新你的证书:

firebase login

3.初始化你的应用,并提供你完成了应用的目录位置:

firebase init

4.最后,将应用部署至 Firebase:

firebase deploy

5.祝贺你。你完成了,你的应用将会部署在:

https://YOUR-FIREBASE-APP.firebaseapp.com

扩展阅读: Firebase Hosting Guide

亲自尝试

试着将应用添加至你的主屏幕,然后断开网络连接,看看它是否能在离线的情况下很好的工作。

Translated By:

  • By Henry Lim

  • Co-Organizer @ GDG Kuala Lumpur

  • By Yu Wang

  • WangYu is Front End Developer

FROM: https://developers.google.com/web/fundamentals/getting-started/codelabs/your-first-pwapp/?hl=zh-cn

阅读全文 »

发布于 02月07, 2017

整理Linux下Mysql增删用户及权限分配与root密码找回问题

MySql中添加用户,新建数据库,用户授权,删除用户,修改密码

1.新建用户

// 登录MYSQL 
 @>mysql -u root -p 
 @>password

 mysql> set names utf8; 
 // 创建本地用户
 mysql> insert into  mysql.user(Host,User,Password) values( "localhost","test",password("1234") ); 

 // 创建远程用户
 mysql> insert into  mysql.user(Host,User,Password) values( "ip或%","test",password("test") ); 

2.为用户授权

 // 登录MYSQL(有ROOT权限)。我里我以ROOT身份登录. 
 @>mysql -u root -p 
 @>password 

 //首先为用户创建一个数据库(testDB) 
 mysql> create database testDB; 

 //授权test用户拥有testDB数据库的所有权限。 
 mysql> grant all privileges on testDB.* to 'test'@'localhost' identified by '1234'; 

 //刷新系统权限表 
 mysql> flush privileges; 

指定部分权限给用户::

mysql> grant select,update on testDB.* to 'test'@'localhost' identified by '1234'; 
//刷新系统权限表。 
mysql>flush privileges; 

给root用户授权远程连接权限:

mysql> Grant all privileges on *.* to 'root'@'%' identified by 'password123' with grant option;

//刷新系统权限表。 mysql>flush privileges;

3.删除用户

 @>mysql -u root -p 
 @>password
 mysql> Delete FROM user Where User="test" and Host="localhost"; 
 mysql> flush privileges; 
 //删除用户的数据库 
 mysql>drop database testDB; 

4.修改指定用户密码

@>mysql -u root -p 
@>password 
mysql> update mysql.user set password=password('新密码') where User="test" and Host="localhost"; 
mysql> flush privileges; 

5.列出所有数据库

mysql>show database; 

6.切换数据库

mysql>use '数据库名';

7.列出所有表

mysql>show tables; 

8.显示数据表结构

mysql>desc 表名; 

9.删除数据库和数据表

mysql>drop database 数据库名; 
mysql>drop table 数据表名;

忘记mysql root密码解决办法

1.编辑MySQL配置文件my.cnf

vi /etc/my.cnf    #编辑my.cnf文件

找到[mysqld],在下面添加一行skip-grant-tables

[mysqld]

skip-grant-tables

:wq!  #保存退出

service mysqld restart #重启MySQL服务

2.进入MySQL控制台

mysql -uroot -p   #直接按回车,这时不需要输入root密码。

3.修改root密码

update mysql.user set password=password('123456') where User="root" and Host="localhost";

注意⚠️:Mysql5.7+版本 user表并没有password字段,按照如下修改:

update mysql.user set authentication_string=password('123456') where User="root" and Host="localhost";


flush privileges;  #刷新系统授权表


grant all on *.* to 'root'@'localhost' identified by '123456' with grant option;

4、取消/etc/my.cnf中的skip-grant-tables

vi /etc/my.cnf   #编辑文件,找到[mysqld],删除skip-grant-tables这一行

:wq!  #保存退出

5、重启mysql

service mysqld restart    #重启mysql,这个时候mysql的root密码已经修改为123456

6、进入mysql控制台

mysql -uroot -p  #进入mysql控制台

123456 #输入密码

7、远程Mysql无法链接,开放3306(默认)端口

vi /etc/sysconfig/iptables
-A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 3306-j ACCEPT
#保存,并重启iptables(如果设置自动生效可忽略)
service iptables restart

阅读全文 »

发布于 02月07, 2017

整理centos6.5服务器上web环境部署svn的问题

centos6.5+ 服务器上搭建SVN服务器并实现自动同步至web目录:

预期

1.仓库目录 /home/svn/ 下,并且仓库名为 project;

2.创建用户组test,该组下添加两个成员test01、test02,密码同用户名,两用户可以checkout代码和提交代码;

3.利用Hooks实现svn代码更新的时候自动同步至web目录(web目录在 /home/www/ 下)。

一、搭建svn环境并创建仓库:

1、yum安装Subversion:

yum install -y subversion

2、检测是否安装成功(查看svn版本号)

 svnserve --version

3、创建版本库

 //先建目录
 cd /home/svn

 //创建版本库
 svnadmin create /home/svn/project

 cd project
 //会看到自动生成的版本库文件
 conf  db  format  hooks  locks  README.txt

至此,svn环境搭建成功。

二、创建用户组及用户:

1、 进入版本库中的配置目录conf,此目录有三个文件: svn服务综合配置文件(svnserve.conf)、 用户名口令文件(passwd)、权限配置文件(authz)。

2、修改权限配置文件:vim authz

3、配置用户名命令文件:vim passwd

4、配置SVN服务综合配置文件:svnserve.conf

 //找到以下配置项,将前面的#号去掉,然后做相应的配置
 anon-access = none  //匿名用户访问权限:无
 auth-access = write     //普通用户访问权限:读、写
 password-db = passwd        //密码文件
 authz-db = authz        //权限配置文件
 realm = /home/svn/project    //版本库所在

注意:所有以上的配置项都需要顶格,即前面不能预留空格,否则报错

5、启动svn服务:

svnserve -d -r /home/svn

如果提示:

svnserve: E000098: Can't bind server socket: Address already in use 证明现在svn已经被启动了,由于我们修改了配置文件,因此要重启svn服务

 //查看svn服务详情
 ps aux | grep svn
 //将svn服务强制停止  其中790为svn服务的ID号,-9是kill的参数
 kill -9 790

或者用

 killall svnserve

再运行 svnserve -d -r /home/svn,进行启动服务;此处建议直接运行:

 svnserve -d -r /home

(注:解决部分情况下运行/home/svn不生效问题)

6、测试服务器:

 //我们在web目录测试(/home/wwwcd /home/www
 svn co svn://IP地址/project

如果提示:Checked out revision 1. 表示checkout成功

我们添加新文件来测试是否提交成功:

 cd /home/www
 touch index.php
 svn add index.php   //成功的话会显示  A index.php
 svn commit index.php -m "测试提交文件"

若最后提示:

 Adding         index.php
 Transmitting file data .
 Committed revision 2.

则表示我们svn服务器成功搭建!

7、本地checkout(具体操作忽略~)

三、实现svn更新自动同步到web目录:

1、在web目录中checkout版本库,关键的一步:

 svn co svn://IP地址/project /home/www --username test01(SVN账号) --test01(SVN密码)

进入/home/svn/project/hooks下,建立post-commit文件:

 cd /var/svn/project/hooks
 vim post-commit

 //在该文件里添加如下代码,保存
 #!/bin/sh
 #设定环境变量,如果没有设定可能会出现update报错
 #设定语言,根据系统语言设置,如果是GBK就设置为 LANG=zh_CN.GBK
 export LANG=en_US.utf8
 SVN_PATH=/usr/bin/svn   //这里不用改
 WEB_PATH=/home/www  //web目录,如果你的不同,可以改
 //这里的用户随便一个就好
 $SVN_PATH update $WEB_PATH --username 'test01' --password 'test01' --  no-auth-cache

保存退出。

修改post-commit用户为www(自行依据本地环境修改)目录用户:

chown www:www post-commit

增加post-commit 执行权限:

chmod 755 post-commit

四、给SVN控制的项目添加忽略文件/文件夹:

1.未加入控制的文件夹

svn propset svn:ignore 'test' .
svn update
svn commit -m "add a ignore dir"

2.已经加入版本控制的文件夹

svn export test test_bak
svn rm test
svn commit -m "delete test"
mv test_bak test
svn propset svn:ignore 'test' .
svn update
svn commit -m "add a ignore dir"

注意: 后面的 “ .“ 标点

3.如果忽略一个目录下多个文件夹的话,如下

svn propset svn:ignore 'test
    test1
    test2' .

注意:每一个文件夹要单独另起一行

阅读全文 »

发布于 01月28, 2017

Centos6.X 安装 wkhtmltoimage 生成图片

1. wkhtmltoimage安装 :

wget http://wkhtmltopdf.googlecode.com/files/wkhtmltoimage-0.10.0_rc2-static-i386.tar.bz2

tar jxf wkhtmltoimage-0.10.0_rc2-static-i386.tar.bz2\r\ncp wkhtmltoimage-i386 /usr/local/bin/wkhtmltoimage

64位

wget http://wkhtmltopdf.googlecode.com/files/wkhtmltoimage-0.10.0_rc2-static-amd64.tar.bz2
mv wkhtmltoimage-0.10.0_rc2-static-amd64.tar.bz2 wkhtmltoimage-0.10.0_rc2-static-amd64.tar
tar -xvf wkhtmltoimage-0.10.0_rc2-static-amd64.tar\r\nmv wkhtmltoimage-amd64 /usr/bin/wkhtmltoimage

安装成功,测试 wkhtmltoimage http://www.baidu.com/ screenshot.png

2、php执行wkhtmltoimage 生成图片:

set_time_limit(0);
shell_exec('/usr/local/bin/wkhtmltoimage http://www.baidu.com/ /usr/local/wwwroot/111cn.net/5eyi.jpg');

阅读全文 »