<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>逸侨Blog</title>
        <description>一位90后个人技术博客</description>
        <link>http://yiqiao.me</link>
        <atom:link href="http://yiqiao.me/feed.xml" rel="self" type="application/rss+xml"/>
                <pubDate>Thu, 11 Jun 2026 03:18:03 +0000</pubDate>
        <lastBuildDate>Thu, 11 Jun 2026 03:18:03 +0000</lastBuildDate>
        <generator>逸侨</generator>
                    <item>
                <title>记一次 PHP fn 闭包查询问题</title>
                <link>http://yiqiao.me/articles/45/a-php-fn-closure-query-problem</link>
                <description>&lt;p&gt;最近在使用箭头函数遇到一些问题&lt;/p&gt;
&lt;h3&gt;Laravel 中箭头函数 (fn) 的意义与局限性&lt;/h3&gt;
&lt;h4&gt;1. 设计初衷与优势&lt;/h4&gt;
&lt;ul&gt;&lt;li&gt;提供&lt;strong&gt;语法糖&lt;/strong&gt;，简化简单闭包的代码书写&lt;/li&gt;
&lt;li&gt;自动 return，书写更简洁&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;2. 适用场景&lt;/h4&gt;
&lt;ul&gt;&lt;li&gt;&lt;strong&gt;推荐用法&lt;/strong&gt;：单行、简单条件筛选&lt;br /&gt;&lt;code&gt;-&amp;gt;where(fn($q) =&amp;gt; $q-&amp;gt;where(&#039;status&#039;, 1))&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;链式简单条件&lt;/strong&gt;：通常也可用&lt;br /&gt;&lt;code&gt;-&amp;gt;where(fn($q) =&amp;gt; $q-&amp;gt;where(&#039;role&#039;, &#039;admin&#039;)-&amp;gt;orWhere(&#039;score&#039;, &#039;&amp;gt;&#039;, 100))&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;3. 局限性与底层原因&lt;/h4&gt;
&lt;ul&gt;&lt;li&gt;Laravel 通过反射分析闭包，箭头函数的单表达式边界模糊&lt;/li&gt;
&lt;li&gt;对于复杂嵌套/多行/JSON 查询，箭头函数可能表达不清，推荐用传统闭包&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;4. 最佳实践建议&lt;/h4&gt;
&lt;ul&gt;&lt;li&gt;简单查询优先选择箭头函数&lt;/li&gt;
&lt;li&gt;复杂逻辑、嵌套、JSON 操作务必使用传统闭包&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;5. 总结&lt;/h4&gt;
&lt;ul&gt;&lt;li&gt;箭头函数提升了简单查询的开发体验和代码可读性&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;复杂场景建议用传统闭包&lt;/strong&gt;，二者结合使用效果最佳&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;一句话总结&lt;/strong&gt;：箭头函数让简单查询更简洁，复杂逻辑要用传统闭包，灵活切换最优。&lt;/p&gt;</description>
                <pubDate>Wed, 20 Aug 2025 03:43:45 UTC</pubDate>
                <author>1403749842@qq.com (yiqiao)</author>
                <guid>http://yiqiao.me/articles/45/a-php-fn-closure-query-problem</guid>
                <category>PHP</category>
            </item>
                    <item>
                <title>记录一次在 PHP 中 base64 解码出现乱码</title>
                <link>http://yiqiao.me/articles/44/record-one-occurrence-of-garbled-code-during-base64-decoding-in-php</link>
                <description>&lt;h3&gt;最近遇到一个 base64 解码在 PHP 出现异常，使用在线工具解码也有问题，研究一下解决方案&lt;/h3&gt;
&lt;h3&gt;1. 确认字符编码&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;mb_internal_encoding(&#039;UTF-8&#039;);&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. 检查Base64字符串的完整性和格式&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;function addBase64Padding($base64Str) {
    $len = strlen($base64Str);
    $padding = 4 - ($len % 4);
    if ($padding !== 4) {
        $base64Str .= str_repeat(&#039;=&#039;, $padding);
    }
    return $base64Str;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3. 处理 URL 安全的Base64 字符串&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;function convertUrlSafeBase64($base64Str) {
    // 将URL安全字符转换为标准Base64字符
    $base64Str = strtr($base64Str, &#039;-_&#039;, &#039;+/&#039;);
    // 添加填充符号
    $base64Str = addBase64Padding($base64Str);
    return $base64Str;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4. 调用&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;在 PHP 中使用 &lt;code&gt;base64_decode()&lt;/code&gt; 函数解码 &lt;code&gt;Base64&lt;/code&gt; 字符串。可以启用严格模式，确保只解码有效的 &lt;code&gt;Base64&lt;/code&gt; 字符串&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;$base64Str = &quot;YmFzZTY0U3Ry&quot;;
$standardBase64Str = convertUrlSafeBase64($base64Str);
$decodedStr = base64_decode($standardBase64Str, true); // true表示启用严格模式
echo $decodeedStr;&lt;/code&gt;&lt;/pre&gt;</description>
                <pubDate>Fri, 09 May 2025 09:12:52 UTC</pubDate>
                <author>1403749842@qq.com (yiqiao)</author>
                <guid>http://yiqiao.me/articles/44/record-one-occurrence-of-garbled-code-during-base64-decoding-in-php</guid>
                <category>PHP</category>
            </item>
                    <item>
                <title>Docker 中使用 directus flow 功能修改数据库案例</title>
                <link>http://yiqiao.me/articles/43/case-study-of-using-directus-flow-function-to-modify-database-in-docker</link>
                <description>&lt;p&gt;最近在研究 headless ，directus 深得喜爱，于是就打算做个 blog 功能。在做的过程发现想创建过程后对某个 value 值修改可以用 flows 功能就折腾了一下，官方文档写的太简单了。查了好多资料才处理完成。&lt;/p&gt;
&lt;p&gt;先照葫芦画瓢：&lt;a href=&quot;https://docs.directus.io/guides/extensions/operations-npm-package.html&quot;&gt;创建自己的操作&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; cd extensions
 npx create-directus-extension@latest
第一步选择 operation，
取名: xxx
我选择了: Typescript
安装好后会自动创建个文件夹在 extensions 中，
创建好后直接 npm run dev

这里我遇到第一个坑就是无法热加载拓展，修改 `docker-compose.yml` 在 `environment` 新增 `EXTENSIONS_AUTO_RELOAD: &quot;true&quot;`，再重启 docker 服务&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;跟着文档内容后把你要修改的内容传过去&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;return {
            id: id,
            content: text,
};&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;再 flows 中新增一个更新数据项目，例如：
&lt;img src=&quot;https://pic1.imgdb.cn/item/6787861fd0e0a243d4f4872b.png&quot; alt=&quot;update data&quot; /&gt;&lt;/p&gt;
&lt;p&gt;最后就成功啦。
参考资料:
&lt;a href=&quot;https://juejin.cn/post/7299663440704192562&quot;&gt;低代码平台directus 实战半年-提升篇flow&lt;/a&gt;
&lt;a href=&quot;https://juejin.cn/post/7301342025880780809&quot;&gt;低代码平台directus 实战半年-进阶篇&lt;/a&gt;&lt;/p&gt;</description>
                <pubDate>Wed, 15 Jan 2025 10:00:24 UTC</pubDate>
                <author>1403749842@qq.com (yiqiao)</author>
                <guid>http://yiqiao.me/articles/43/case-study-of-using-directus-flow-function-to-modify-database-in-docker</guid>
                <category>前端</category>
            </item>
                    <item>
                <title>关于 dcat-admin 使用 multipleSelectTable 选择后默认是 name 字段</title>
                <link>http://yiqiao.me/articles/42/regarding-dcat-admin-using-multipleselecttable-to-select-defaults-to-the-name-field</link>
                <description>&lt;p&gt;最近用 dcat-admin 使用 multipleSelectTable 后发现选择项目不是我想要的。默认带出了 name 参数，提交后重新刷新又是正常的，排查了 select-table.js 后确认了是取了table 里边的 checkbox 中 data-id 和 data-label 的值再翻了下 grid 源码后，最终解决方案如下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$form-&amp;gt;multipleSelectTable(&#039;sku&#039;, &#039;商品&#039;)
                -&amp;gt;from(ThinkGoodSkuTable::make())
                -&amp;gt;dialogWidth(&#039;1000px&#039;)
                -&amp;gt;options(function () use ($form) { // 设置编辑数据显示
                    if($form-&amp;gt;model()-&amp;gt;type == Coupon::TYPE_EXCHANGE){
                        $v = $form-&amp;gt;model()-&amp;gt;rules;
                        if (! $v) {
                            return [];
                        }
                        return ThinkGoodSku::with(&#039;thinkGoods&#039;)-&amp;gt;whereIn(&#039;id&#039;, $v)-&amp;gt;get()-&amp;gt;pluck(&#039;thinkGoods.name&#039;, &#039;id&#039;);
                    }
                })-&amp;gt;value($form-&amp;gt;model()-&amp;gt;rules);&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;class ThinkGoodSkuTable extends LazyRenderable
{
    public function grid(): Grid
    {
        return Grid::make(ThinkGoodSku::with(&#039;thinkGoods&#039;), function (Grid $grid) {
            $grid-&amp;gt;rowSelector()-&amp;gt;titleColumn(&quot;sku&quot;);
            ...
        });
    }
}

如果你想用关联关系可以，关联关系的 key 记得如果是驼峰改成下划线:`$grid-&amp;gt;rowSelector()-&amp;gt;titleColumn(&quot;think_good.name&quot;);`&lt;/code&gt;&lt;/pre&gt;</description>
                <pubDate>Wed, 15 Jan 2025 03:42:39 UTC</pubDate>
                <author>1403749842@qq.com (yiqiao)</author>
                <guid>http://yiqiao.me/articles/42/regarding-dcat-admin-using-multipleselecttable-to-select-defaults-to-the-name-field</guid>
                <category>PHP</category>
            </item>
                    <item>
                <title>关于 Git 拉取记录会自动合并问题</title>
                <link>http://yiqiao.me/articles/41/regarding-the-issue-of-automatic-merging-of-git-pulled-records</link>
                <description>&lt;blockquote&gt;
&lt;p&gt;因为有强迫症，从远程拉去后发现需要自动合并，从而生成一条 Merge 记录
这样对 git commit 记录很不理想，查询资料后发现配置一条语句即可。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git config --global pull.rebase true&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Git 合并多个 commit&lt;/h3&gt;
&lt;h4&gt;1. git log 查询提交记录&lt;/h4&gt;
&lt;p&gt;首先你要知道自己想合并的是哪几个提交，可以使用 &lt;code&gt;git log --oneline&lt;/code&gt; 命令来查看提交历史。&lt;/p&gt;
&lt;h4&gt;2. git rebase&lt;/h4&gt;
&lt;p&gt;指名要合并的版本之前的版本号&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git rebase -i 559723ac&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;tip: 559723ac 是不参与合并的&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;3.选取要合并的提交&lt;/h4&gt;
&lt;h5&gt;1.执行了 &lt;code&gt;rebase&lt;/code&gt; 命令之后，会弹出一个窗口，头几行如下：&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;pick xxxxxx &#039;commit content&#039;
pick xxxxxx &#039;commit content&#039;
pick xxxxxx &#039;commit content&#039;&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;2. 将 pick 改为 &lt;code&gt;squash&lt;/code&gt; 或者 &lt;code&gt;s&lt;/code&gt;，之后保存并关闭文本编辑窗口即可。改完之后文本内容如下：&lt;/h5&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;pick xxxxxx &#039;commit content&#039;
s xxxxxx &#039;commit content&#039;
s xxxxxx &#039;commit content&#039;&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;3. 然后保存退出，Git 会压缩提交历史，如果有冲突，需要修改，修改的时候要注意，保留最新的历史，不然我们的修改就丢弃了。修改以后要记得敲下面的命令：&lt;/h5&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git add -A
git rebase --continue&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;如果你想放弃这次压缩的话，执行以下命令：&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git rebase --abort&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;4.如果没有冲突，或者冲突已经解决，则会出现编辑窗口&lt;/h5&gt;
&lt;h5&gt;5. 输入 wq 保存并退出, 再次输入 git log 查看 commit 历史信息，你会发现这两个 commit 已经合并了。&lt;/h5&gt;
&lt;blockquote&gt;
&lt;p&gt;让远程分支更加好看&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git pull --rebase --autostash origin master&lt;/code&gt;&lt;/pre&gt;</description>
                <pubDate>Sat, 21 Dec 2024 09:01:53 UTC</pubDate>
                <author>1403749842@qq.com (yiqiao)</author>
                <guid>http://yiqiao.me/articles/41/regarding-the-issue-of-automatic-merging-of-git-pulled-records</guid>
                <category>版本控制</category>
            </item>
                    <item>
                <title>关于windows 11 wsl2 本地IP 重启变动问题</title>
                <link>http://yiqiao.me/articles/40/regarding-the-issue-of-windows-11-wsl2-local-ip-restart-and-change</link>
                <description>&lt;p&gt;最近苹果系统用不了，回来体验了window，安装 wls 2 很丝滑，但是发现在Linux 上配置了 host 后，本地也配置host 重启后发现 Linux  上 host 变更，网上搜搜了发现都需要脚本去处理，由于我安装的是最新的 Win 11 系统（23H2），不需要这么麻烦，步骤如下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;在 C:\Users\你的用户 下边创建一个 `.wslconfig` 文件，内容为：
[wsl2]
autoMemoryReclaim=gradual  
networkingMode=mirrored
dnsTunneling=true
firewall=true
autoProxy=true
配置后，再把hosts 都改成 127.0.0.1就好了&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果你不知道怎么改，可以先右键创建文本文件，在文件管理器 &lt;code&gt;Win + E&lt;/code&gt; 点击顶部的「查看」&amp;gt;「显示」，勾选和取消勾选「文件扩展名」选项，可以显示和隐藏文件后缀。再把刚刚创建的文件去除掉 &lt;code&gt;.txt&lt;/code&gt; 即可
最后，还是用 macOS 舒服，没有这么多烦恼。&lt;/p&gt;</description>
                <pubDate>Sat, 30 Nov 2024 17:34:27 UTC</pubDate>
                <author>1403749842@qq.com (yiqiao)</author>
                <guid>http://yiqiao.me/articles/40/regarding-the-issue-of-windows-11-wsl2-local-ip-restart-and-change</guid>
                <category>Linux</category>
            </item>
                    <item>
                <title>在宝塔中针对不同 PHP 版本执行 composer 命令</title>
                <link>http://yiqiao.me/articles/39/execute-composer-commands-for-different-php-versions-in-the-pagoda</link>
                <description>&lt;p&gt;最近更新宝塔后发现在每个项目中 &lt;code&gt;composer&lt;/code&gt;项不见了。&lt;/p&gt;
&lt;p&gt;如果执行在默认php 版本为 7.4，在8.0 项目中执行 &lt;code&gt;comopser update&lt;/code&gt; 会失败。&lt;/p&gt;
&lt;p&gt;不想更换默认php 版本，而且来回切换也很烦&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;查了下资料执行以下命令即可：
以 php8.0 为例:&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;/www/server/php/80/bin/php /usr/bin/composer install/update&lt;/code&gt;&lt;/pre&gt;</description>
                <pubDate>Thu, 11 Apr 2024 08:16:56 UTC</pubDate>
                <author>1403749842@qq.com (yiqiao)</author>
                <guid>http://yiqiao.me/articles/39/execute-composer-commands-for-different-php-versions-in-the-pagoda</guid>
                <category>PHP</category>
            </item>
                    <item>
                <title>使用 Jmeter TCP/UDP 性能测试</title>
                <link>http://yiqiao.me/articles/38/using-jmeter-tcpudp-performance-testing</link>
                <description>&lt;blockquote&gt;
&lt;p&gt;最新在做个 TCP 连接，找了好多工具都没有合适的，最终还是选择老牌测试工具 Jmeter &lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;1. 安装&lt;/h3&gt;
&lt;p&gt;由于我是 MacOS，直接用 &lt;code&gt;homebrew&lt;/code&gt; 直接安装省事。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;brew install jemter
安装成功使用 
jemter 调起&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. 配置&lt;/h3&gt;
&lt;h4&gt;1、首先切换下语言&lt;/h4&gt;
&lt;p&gt;切换语言：Options-&amp;gt;Choose Language&lt;/p&gt;
&lt;h4&gt;2、创建测试线程组 Thread Group&lt;/h4&gt;
&lt;h4&gt;3、创建取样器&lt;/h4&gt;
&lt;p&gt;右键-&amp;gt; 添加 -&amp;gt; 取样器 -&amp;gt; TCP 取样器&lt;/p&gt;
&lt;h4&gt;4、取样器配置&lt;/h4&gt;
&lt;p&gt;&lt;img src=&quot;https://pic.imgdb.cn/item/659e86d7871b83018abe32df.jpg&quot; alt=&quot;TCP 取样器&quot; /&gt;
创建取样器后会有一下配置，配置好你的ip 和端口后，还需要个末尾字符参数。否则你的结果树是一直返回错误。
&lt;img src=&quot;https://pic.imgdb.cn/item/659e8791871b83018ac21ac9.jpg&quot; alt=&quot;结果树&quot; /&gt;
如果你的请求结果是16 进制的话；
你还需要配置一个参数在端口上方有个 &lt;code&gt;TCPClient classname&lt;/code&gt;：
当前支持三种格式 &lt;/p&gt;
&lt;ul&gt;&lt;li&gt;1.TCPClientImpl（默认） &lt;/li&gt;
&lt;li&gt;2.BinaryTCPClientImpl &lt;/li&gt;
&lt;li&gt;3.LengthPrefixedBinaryTCPClientImpl&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;如果没有的话，去到项目文件找到 &lt;code&gt;bin&lt;/code&gt; 目录下 &lt;code&gt;jmeter.properties&lt;/code&gt; 文件，设置tcp.handler的值，本例中以传输16进制数据为例。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd /usr/local/Cellar/jmeter/5.6.3/libexec/bin

vi jmeter.properties
tcp.handler=BinaryTCPClientImpl

你还可以直接修改默认语言：
language=zh_CN
支持语言参数有以下：en, fr, de, no, es, tr, ja, zh_CN, zh_TW, pl, pt_BR&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;保存退出。&lt;/p&gt;
&lt;h4&gt;5、 UDP 取样器&lt;/h4&gt;
&lt;p&gt;默认是不带的，需要去插件市场安装
选项-&amp;gt; Plugin Manager
弹出框后选择第二个选择搜索 UDP Protocol Support。安装后在最下边点下应用，重启后取样器里边就有了&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://pic.imgdb.cn/item/659e8a2d871b83018ad064b8.jpg&quot; alt=&quot;安装插件&quot; /&gt;&lt;/p&gt;</description>
                <pubDate>Wed, 10 Jan 2024 12:01:30 UTC</pubDate>
                <author>1403749842@qq.com (yiqiao)</author>
                <guid>http://yiqiao.me/articles/38/using-jmeter-tcpudp-performance-testing</guid>
                <category>Test</category>
            </item>
                    <item>
                <title>Nginx 日志分析工具-GoAccess</title>
                <link>http://yiqiao.me/articles/37/nginx-log-analysis-tool-goaccess</link>
                <description>&lt;blockquote&gt;
&lt;p&gt;最近遇到了服务器访问异常，但是无法定位到，所以就想着根据nginx 日志排查一下那个请求过高了。经过搜索，发现goAccess 不错，就开一篇帖子记录下&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;安装&lt;/h2&gt;
&lt;p&gt;访问官方：&lt;a href=&quot;https://goaccess.io/&quot;&gt;GoAccess&lt;/a&gt; 获取安装包
我这里用的是MacOs，所以直接 &lt;code&gt;brew install goaccess&lt;/code&gt; 即可&lt;/p&gt;
&lt;h2&gt;使用&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;goaccess -a -c -d -f /var/log/nginx/access.log -p /etc/goaccess.conf &amp;gt; /home/test/test.html
-a 开启 UserAgent 列表。开启后会降低解析速度
-c 在程序开始运行时显示 日志/日期 配置窗口
-d 输出 HTML 或者 JSON 报告时开启 IP 解析
-f 指定输入日志文件的路径
-p 指定使用自定义配置文件&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;PS: Mac 路径: /usr/local/Cellar/goaccess/1.7.2/etc/goaccess/goaccess.conf&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;经常出现的错误&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;==8814== GoAccess - version 1.7.2 - Apr  1 2023 02:48:48
==8814== Config file: /usr/local/Cellar/goaccess/1.7.2/etc/goaccess/goaccess.conf
==8814== https://goaccess.io - &amp;lt;hello@goaccess.io&amp;gt;
==8814== Released under the MIT License.
==8814==
==8814== FILE: /xxx-20230703
==8814== 已解析 10 行 出现以下错误:
==8814==
==8814== Token &#039;127.0.0.1 - - [02&#039; doesn&#039;t match specifier &#039;%d&#039;
==8814==
==8814== 格式错误 - 请检查你的日志/日期/时间格式

这时候需要你去 goaccess.conf 配置一下参数
time-format %T
date-format %d/%b/%Y
log-format %h - %^ [%d:%t %^] requesthost:&quot;%v&quot;; &quot;%r&quot; requesttime:&quot;%T&quot;; %s %b &quot;%R&quot; - %^&quot;%u&quot;
注意：这个格式需要根据你nginx 配置生成的格式去匹配，配置不对可能会出现
==8886== Token &#039;+0800]&#039; doesn&#039;t match specifier &#039;%h&#039; 这种错误

或者尝试下以下写法：
# 不会报错，但是生成的是英文格式
LANG=&quot;en_US.UTF-8&quot; bash -c &#039;goaccess www.***.com.log --log-format=COMBINED&#039;
# 不会报错，而且生成的HTML是中文格式
LANG=&quot;zh_CN.UTF-8&quot; LC_TIME=&quot;en_US.UTF-8&quot; bash -c &#039;goaccess www.***.com.log --log-format=COMBINED -o result.html&#039;&lt;/code&gt;&lt;/pre&gt;</description>
                <pubDate>Mon, 03 Jul 2023 08:33:35 UTC</pubDate>
                <author>1403749842@qq.com (yiqiao)</author>
                <guid>http://yiqiao.me/articles/37/nginx-log-analysis-tool-goaccess</guid>
                <category>Linux</category>
            </item>
                    <item>
                <title>Nginx 匹配多个不同的PHP 项目</title>
                <link>http://yiqiao.me/articles/36/nginx-matches-multiple-different-php-projects</link>
                <description>&lt;h2&gt;Nginx 匹配多个不同的PHP 项目&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;最近遇到了需要配置 2 个项目在不同文件夹，域名要配置同一个。研究了下 Nginx 配置终于配置好了。
配置如下：&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;下面是两个 Laravel 应用程序的工作配置，其中一个应用程序存在于另一个应用程序的子目录中。
server {
    listen 80 default_server;
    listen [::]:80 default_server;

    root /var/www/first/public;

    index index.html index.htm index.php;

    server_name _;

    location / {
        try_files $uri $uri/ /index.php$is_args$args;
    }

    location /second {
        alias /var/www/second/public;
        try_files $uri $uri/ @second;

        location ~ \.php$ {
            include fastcgi-php.conf;
            fastcgi_param SCRIPT_FILENAME $request_filename;
            fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
        }
    }

    location @second {
        rewrite /second/(.*)$ /second/index.php?/$1 last;
    }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;两个项目的程序文件实际上并不存在于彼此之间。应用程序 first 存在于 /var/www/first 中，而 second 应用程序存在于 /var/www/second 中。
在我看来，在这种情况下，这是首选的设置，因为嵌套应用程序文件，你“物理地”把一个项目的文件放在另一个项目的文件中，大多数PHP应用程序使用公共目录作为web根目录，这会变得非常混乱。
当然，根据应用程序的不同，你遇到的情况可能会有一些变化，但这不会对本教程产生太大的影响。
我们从一个基本的服务器配置开始，适合于服务单个应用程序:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;server {
    listen 80 default_server;

    root /var/www/first/public;

    index index.html index.htm index.php;

    server_name _;

    location / {
        try_files $uri $uri/ /index.php$is_args$args;
    }

    location ~ \.php$ {
        include fastcgi-php.conf;
        fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这排除了你在生产应用程序中可能需要的一些东西(例如：静态资产的缓存头文件)，但足以让一个PHP应用程序正常工作。我经常静态文件匹配成功，php 文件失败。一定要匹配正确。&lt;/p&gt;
&lt;h3&gt;添加嵌套项目&lt;/h3&gt;
&lt;p&gt;当在子目录中运行第二个应用程序时，我们遇到了一些问题。让我们一起来看看。
首先，我们知道我们想要在子目录 &lt;code&gt;/second&lt;/code&gt; 中运行第二个应用程序(子目录是任意的，我只是选择将其命名为 &lt;code&gt;second&lt;/code&gt;)。因此，我们为“嵌套”位置创建了一个位置块:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;location /second {

}&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;web root:&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我们知道嵌套项目有一个单独的 web root。像我一样，你的第一个倾向可能是设置一个根指向 Nginx 到 &lt;code&gt;/var/www/second/public&lt;/code&gt;，但这最终不起作用! 相反，我们需要使用别名: &lt;code&gt;alias&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;location /second {
    # 把 root 换成 alias + 项目路径
    alias /var/www/second/public;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;alias&lt;/code&gt; 类似于 &lt;code&gt;root&lt;/code&gt;，但具有不同的行为。
&lt;code&gt;Nginx&lt;/code&gt; 结合 &lt;code&gt;root&lt;/code&gt; 和给定的 &lt;code&gt;URI&lt;/code&gt; 在磁盘驱动器上找到一个文件。例如，URI &lt;code&gt;/foo/bar&lt;/code&gt; 将指示 &lt;code&gt;Nginx&lt;/code&gt; 提供 &lt;code&gt;/var/www/first/public/foo/bar&lt;/code&gt;。由于该目录不存在，try_files 部分告诉 Nginx 将请求发送到 /var/www/first/public/index.php。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;所 &lt;code&gt;includ fastcgi-php.conf&lt;/code&gt; 配置负责解析出 &lt;code&gt;/foo/bar&lt;/code&gt; 作为 PHP 应用程序使用的路由的预期 URI。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;code&gt;alias&lt;/code&gt; 的行为并不完全像这样。在我们的例子中，&lt;code&gt;/second&lt;/code&gt; URI 别名为 &lt;code&gt;/var/www/second/public&lt;/code&gt;。因此，&lt;code&gt;/second&lt;/code&gt; 的 URI 将在 &lt;code&gt;/var/www/second/public&lt;/code&gt; 中查找要服务的文件。URI &lt;code&gt;/second/foo&lt;/code&gt; 将指示 Nginx 查找 &lt;code&gt;/var/www/second/public/foo&lt;/code&gt; ；省略了 &lt;code&gt;/second&lt;/code&gt; 部分。
注意区别——使用这个 &lt;code&gt;alias&lt;/code&gt;，Nginx不会像 &lt;code&gt;root&lt;/code&gt; 那样查找 &lt;code&gt;/var/www/alias/public/second/foo&lt;/code&gt; 中的文件。
因此，&lt;code&gt;alias&lt;/code&gt; 具有我们想要的行为——它不会尝试在一些不存在的嵌套目录中查找文件。我们仍然需要从文件 &lt;code&gt;/var/www/second/public/index.php&lt;/code&gt; 中创建一个类似 &lt;code&gt;/second/foo&lt;/code&gt; 服务的URI，所以我们必须添加另一个 &lt;code&gt;try_files&lt;/code&gt;。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;location /second {
    alias /var/www/second/public;
    try_files $uri $uri/ /index.php$is_args$args;
}&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;看起来很眼熟! 但是，我们需要在&lt;code&gt;/second&lt;/code&gt;的位置做一些PHP的事情，所以让我们在那里也得到一个PHP处理程序:&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;location /second {
    alias /var/www/second/public;
    try_files $uri $uri/ /index.php$is_args$args;

    location ~ \.php$ {
        include fastcgi-php.conf;
        fastcgi_param SCRIPT_FILENAME $request_filename;
        fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;PHP 处理程序位置在 &lt;code&gt;location /second{…}&lt;/code&gt;，所以我们可以自定义它一点。
注意，我在PHP位置块中偷偷添加了一些东西。我(重新)设置&lt;code&gt;SCRIPT_FILENAME FastCGI&lt;/code&gt;参数为&lt;code&gt;$request_filename&lt;/code&gt;。这通常是&lt;code&gt;$document_root$fastcgi_script_name&lt;/code&gt;，在我们的配置中，它总是指向 &lt;code&gt;/var/www/first/public/index.php&lt;/code&gt; ——错误的应用程序!
相反，我们使用 &lt;code&gt;$request_filename&lt;/code&gt;，它在Nginx文档中有如下定义:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;当前请求的文件路径，基于 &lt;code&gt;root&lt;/code&gt;或 &lt;code&gt;alias&lt;/code&gt; 指令，以及请求URI。
这样就正确地考虑了 &lt;code&gt;alias&lt;/code&gt;，并将正确的路径传递给嵌套应用程序中的 &lt;code&gt;index.php&lt;/code&gt; 文件。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;工作原理&lt;/h3&gt;
&lt;p&gt;这将在一开始工作! 进入URI &lt;code&gt;/second&lt;/code&gt; 可以正常工作。发生的事情是 &lt;code&gt;/second&lt;/code&gt; 被 &lt;code&gt;alias&lt;/code&gt; 为 &lt;code&gt;/var/www/second/public&lt;/code&gt;,  &lt;code&gt;try_files&lt;/code&gt; 将其发送到 &lt;code&gt;/index.php&lt;/code&gt;，最终正确地为 &lt;code&gt;/var/www/second/public/index.php&lt;/code&gt;
然而，如果我们的应用程序有一个定义的路由(foo，例如)，我们试图前往URI &lt;code&gt;/second/foo&lt;/code&gt; 到达它，我们收到一个 &lt;code&gt;404&lt;/code&gt; 错误!不仅如此，这是一个来自&lt;code&gt;first&lt;/code&gt; 应用程序的404页面!
这个请求最终由外部 PHP 处理程序处理，它使用 &lt;code&gt;$document_root$fastcgi_script_name&lt;/code&gt; 作为 &lt;code&gt;SCRIPT_FILENAME&lt;/code&gt;，因此指向文件  &lt;code&gt;/var/www/first/public/index.php&lt;/code&gt;，并由 &lt;code&gt;first&lt;/code&gt; 应用程序提供服务。&lt;/p&gt;
&lt;p&gt;为了解决这个问题，我们重写了URI，将 &lt;code&gt;index.php&lt;/code&gt; 放在 &lt;code&gt;Nginx&lt;/code&gt; 眼中的正确位置。&lt;/p&gt;
&lt;h4&gt;重写&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;location /second {
    alias /var/www/second/public;
    try_files $uri $uri/ @second;

    location ~ \.php$ {
        include fastcgi-php.conf;
        fastcgi_param SCRIPT_FILENAME $request_filename;
        fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
    }
}

location @second {
    rewrite /second/(.*)$ /second/index.php?/$1 last;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我们调整 &lt;code&gt;try_files&lt;/code&gt; 以将请求发送到 &lt;code&gt;@second&lt;/code&gt;，然后将 &lt;code&gt;@second&lt;/code&gt; 定义为命名位置块。
这个位置块重写URI，因此 &lt;code&gt;/second/foo&lt;/code&gt; 变成 &lt;code&gt;/second/index.php/foo&lt;/code&gt;。最后一个指令告诉 Nginx 使用新的、重写的URI，并将其与其他位置块进行匹配。
Nginx然后重新到达 &lt;code&gt;location /second{…}&lt;/code&gt;，在那里它被正确地解析! &lt;code&gt;index.php&lt;/code&gt; 文件在磁盘上的正确位置，并且包含的 &lt;code&gt;fastcgi-php.conf&lt;/code&gt; 配置正常地从 &lt;code&gt;URI&lt;/code&gt; 的其余部分解析出 &lt;code&gt;foo&lt;/code&gt; 路由(如果你好奇的话，可以通过 &lt;code&gt;fastcgi_split_path_info&lt;/code&gt;)。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;不要忘记上面解释的 &lt;code&gt;SCRIPT_FILENAME&lt;/code&gt; FastCGI 参数所需要的更改。它将我们正确解析的脚本文件路径发送到 &lt;code&gt;PHP-FPM&lt;/code&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;最后附带 Thinkphp 项目的配置&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;server
{
    listen 80;
    root ···;
    ···
    location /second {
            alias /www/wwwroot/second;
            if (!-e $request_filename) {
                rewrite  ^/(.*)$  /second/index.php?s=$1  last;
                break;
            }
            location ~ \.php$ {
                include fastcgi.conf;
                fastcgi_param SCRIPT_FILENAME $request_filename;
                fastcgi_pass  unix:/tmp/php-cgi-74.sock;
            }
        }
}&lt;/code&gt;&lt;/pre&gt;</description>
                <pubDate>Fri, 24 Feb 2023 17:33:27 UTC</pubDate>
                <author>1403749842@qq.com (yiqiao)</author>
                <guid>http://yiqiao.me/articles/36/nginx-matches-multiple-different-php-projects</guid>
                <category>Http 服务器</category>
            </item>
                    <item>
                <title>重写 Laravel Notification 实现自定义字段</title>
                <link>http://yiqiao.me/articles/35/override-larravel-notification-to-implement-custom-fields</link>
                <description>&lt;p&gt;最近开发站内信功能，由于是半路接入的，本来可以用laravel 自带的 notifications 一套开发，
但由于 App 直接接口已经固定是自增id，无法调整notification 的uuid，且mysql 无法再创建一个自增主键，
由于时间关系，，没法再写一套这个站内信，只能用重写方法，来兼容 app 接口。&lt;/p&gt;
&lt;p&gt;查阅资料，Laravel是从toDatabase() 方法返回的数组将被json编码并保存到 data 列中。没办法直接改。
一个解决方法是创建一个新的通道类，扩展 Laravel 的类并覆盖send方法，然后将新类注入到容器中，
而不是 Laravel的原生类中，现在让我们看看如何做到这一点。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;php artisan make:channel DatabaseChannel&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;?php

namespace App\Channels;

use Illuminate\Notifications\Notification;
use Illuminate\Support\Facades\Redis;
use Illuminate\Notifications\Channels\DatabaseChannel as IlluminateDatabaseChannel;

class DatabaseChannel extends IlluminateDatabaseChannel
{
    /**
    * Send the given notification.
    *
    * @param mixed $notifiable
    * @param \Illuminate\Notifications\Notification $notification
    * @return \Illuminate\Database\Eloquent\Model
    */
    public function send($notifiable, Notification $notification)
    {
                //通过redis 实现自增
                $incrId = Redis::connection()-&amp;gt;incr(&#039;notifications&#039;);
        return $notifiable-&amp;gt;routeNotificationFor(&#039;database&#039;)-&amp;gt;create([
            &#039;id&#039;      =&amp;gt; $notification-&amp;gt;id,
            &#039;type&#039;    =&amp;gt; get_class($notification),
            &#039;auto_id&#039;=&amp;gt; $notification-&amp;gt;auto_id ?? null,
            &#039;data&#039;    =&amp;gt; $this-&amp;gt;getData($notifiable, $notification),
            &#039;read_at&#039; =&amp;gt; null,
        ]);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;注意要保存的列中添加了“auto_id”，设置 auto_id 就像向要发送的特定通知类添加属性一样简单。
现在我们需要注入这个类而不是原生的那个，我们可以在任何服务提供者的引导方法中这么做，
我刚刚在App\Providers\AppServiceProvider中这么做了，
你可以为此创建一个服务提供者，但我认为现在这是好的。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;use App\Channels\DatabaseChannel;
use Illuminate\Notifications\Channels\DatabaseChannel as IlluminateDatabaseChannel;

.
.
.

/**
* Bootstrap any application services.
*/
public function boot()
{
    $this-&amp;gt;app-&amp;gt;instance(IlluminateDatabaseChannel::class, new DatabaseChannel);

}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;重写在你需要通知的类&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;use App\Channels\DatabaseChannel;
.
.
.

public function via($notifiable)
{
    return [DatabaseChannel::class];
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最后不要忘记加上迁移文件&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;php artisan make:migration add_auto_id_column_to_notifications_table --table=notifications&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;public function up()
{
    Schema::table(&#039;notifications&#039;, function (Blueprint $table) {
        $table-&amp;gt;integer(&#039;auto_id&#039;)-&amp;gt;unsigned()-&amp;gt;after(&#039;type&#039;)-&amp;gt;nullable();
    });
}

public function down()
{
    Schema::table(&#039;notifications&#039;, function (Blueprint $table) {
        $table-&amp;gt;dropDolumn(&#039;auto_id&#039;);
    });
}

php artisan migrate&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;总结：给 API 提供接口一定要先想好。不然后续修改兼容真的是难受。🤷🏼‍♂️🤷🏼‍♂️🤷🏼‍♂️&lt;/p&gt;</description>
                <pubDate>Mon, 17 Oct 2022 08:36:05 UTC</pubDate>
                <author>1403749842@qq.com (yiqiao)</author>
                <guid>http://yiqiao.me/articles/35/override-larravel-notification-to-implement-custom-fields</guid>
                <category>Laravel</category>
            </item>
                    <item>
                <title>dcat-admin 实现 phpword 读取内容</title>
                <link>http://yiqiao.me/articles/34/dcat-admin-implements-phpword-reading-content</link>
                <description>&lt;blockquote&gt;
&lt;p&gt;最近有个需求，运营太懒了不想在富文本里面编辑，直接给个word 自动处理。研究了一下并用 laravel，dcat-admin 后台实现，下面附下代码：&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;先安装 phpword ：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-basn&quot;&gt;composer require phpoffice/phpword&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;后台代码：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;$form-&amp;gt;tab(&#039;Basic Info&#039;, function(Form $form){
                $form-&amp;gt;file(&#039;word&#039;)-&amp;gt;autoUpload();
                $form-&amp;gt;ignore(&#039;word&#039;);
            })-&amp;gt;tab(&#039;Content&#039;, function(Form $form){
                $form-&amp;gt;editor(&#039;body&#039;)-&amp;gt;imageDirectory(&#039;editor/images/tutorials&#039;)-&amp;gt;width(10, 1);
            })-&amp;gt;saving(function (Form $form) {
                if(request(&#039;word&#039;)){
                    $file = request(&#039;word&#039;);
                    $sections = \PhpOffice\PhpWord\IOFactory::load(public_path(&#039;uploads/&#039;).$file)-&amp;gt;getSections();
                    $html = &#039;&#039;;
                    //循环所有元素
                    foreach ($sections as $section) {
                        foreach ($section-&amp;gt;getElements() as $ele1) {
                            if ($ele1 instanceof \PhpOffice\PhpWord\Element\TextRun) {
                                foreach ($ele1-&amp;gt;getElements() as $ele2) {
                                    if ($ele2 instanceof \PhpOffice\PhpWord\Element\Text) {
                                        $html .= mb_convert_encoding($ele2-&amp;gt;getText(), &#039;GBK&#039;, &#039;UTF-8&#039;);
                                    } elseif ($ele2 instanceof \PhpOffice\PhpWord\Element\Image) {
                                        $imageDataTmp = $ele2-&amp;gt;getImageStringData(true);
                                        $imageType = $ele2-&amp;gt;getImageType() ? : &#039;image/jpg&#039;;
                                        $imageData = &#039;data:&#039; . $imageType . &#039;;base64,&#039; . str_replace(array(&quot;\r\n&quot;, &quot;\r&quot;, &quot;\n&quot;), &quot;&quot;, $imageDataTmp);

                                        $imageSrc = &#039;./uploads/editor/images/tutorials/&#039; . md5($ele2-&amp;gt;getSource()) . &#039;.&#039; . $ele2-&amp;gt;getImageExtension();
                                        file_put_contents($imageSrc, base64_decode(explode(&#039;,&#039;,$imageData)[1]));
                                        $filePath = config(&#039;app.url&#039;).&quot;/uploads/editor/images/tutorials/&quot; . md5($ele2-&amp;gt;getSource()) . &#039;.&#039; . $ele2-&amp;gt;getImageExtension();
                                        $html .= &quot;&amp;lt;img src=$filePath style=&#039;width:100%;height:auto&#039; /&amp;gt;&quot;;
                                    }
                                }
                            }
                        }
                    }
                    $html = mb_convert_encoding($html, &#039;UTF-8&#039;, &#039;GBK&#039;);
                    $form-&amp;gt;body = $html;
                }
            });&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;可能出现的问题：&lt;/p&gt;
&lt;ol&gt;&lt;li&gt;文件类型问题，word模板文件另存为其他格式。如：docx&lt;/li&gt;
&lt;li&gt;检查 php 是否有权限打开文件&lt;/li&gt;
&lt;li&gt;检查 php 是否有操作 tmp 系统缓存文件的权限&lt;/li&gt;
&lt;/ol&gt;&lt;/blockquote&gt;</description>
                <pubDate>Wed, 14 Sep 2022 09:29:05 UTC</pubDate>
                <author>1403749842@qq.com (yiqiao)</author>
                <guid>http://yiqiao.me/articles/34/dcat-admin-implements-phpword-reading-content</guid>
                <category>Laravel</category>
            </item>
                    <item>
                <title>解决 WARP 登录 github 后无法启用问题</title>
                <link>http://yiqiao.me/articles/33/solve-the-problem-that-warp-cannot-be-enabled-after-logging-in-to-github</link>
                <description>&lt;p&gt;最近看上了一个终端工具&lt;a href=&quot;https://www.warp.dev/&quot;&gt;warp&lt;/a&gt;，是用 Rust 写的，于是下载体验一下。
下载后由于目前是内测阶段需要登录 github 授权，不过登录后提示打开 APP 时未响应。这就来解决这个 bug
如果你也遇到这个问题，可以试试我的办法，此办法需要代理 &lt;code&gt;ClashX Pro&lt;/code&gt;  的一些配置。&lt;/p&gt;
&lt;h2&gt;1. 添加代理和执行 WARP .stable 文件&lt;/h2&gt;
&lt;p&gt;首先你需要复制你的代理到你的终端。
我的代理端口是 &lt;code&gt;7890&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;export https_proxy=http://127.0.0.1:7890
http_proxy=http://127.0.0.1:7890 
all_proxy=socks5://127.0.0.1:7890 #这个可以不用&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后去 &lt;code&gt;/Applications/Warp.app/Contents/MacOS&lt;/code&gt; 执行 &lt;code&gt;./stable&lt;/code&gt; 方法&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;cd /Applications/Warp.app/Contents/MacOS
./stable&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;2. 使用 ClashX Pro&lt;/h2&gt;
&lt;h3&gt;第 1 步：下载 ClashX Pro 或其他增强模式&lt;/h3&gt;
&lt;p&gt;你需要确保你有一个基于规则的 Mac 增强模式代理。
可以去这里下载：&lt;a href=&quot;https://install.appcenter.ms/users/clashx/apps/clashx-pro/distribution_groups/public&quot;&gt;ClashX Pro&lt;/a&gt;
为什么我们需要具有增强模式的基于规则的代理？&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;WARP 可能不识别系统代理设置。
使用增强模式可以使基于规则的代理处理所有应用程序。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;第 2 步：确认打开增强模式&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://pic.imgdb.cn/item/625392fa239250f7c50ebb86.jpg&quot; alt=&quot;click enhanced Mode&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;第 3 步：打开配置文件&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://pic.imgdb.cn/item/625393d9239250f7c51017d9.jpg&quot; alt=&quot;open config file&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;第 4 歩： 配置 config.yaml 文件&lt;/h3&gt;
&lt;p&gt;将这些规则添加到您的配置文件中。
&lt;code&gt;🍃 Proxies&lt;/code&gt; 是我配置的名称。也许命名代理、代理或其他。请检查并更换。这取决于你的代理组在配置文件中的配置方式。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# &amp;gt; Warp
- DOMAIN,*.googleapis.com,🍃 Proxies
- DOMAIN,*.warp.dev,🍃 Proxies
- DOMAIN,*.segment.io,🍃 Proxies
- DOMAIN,*.sentry.io,🍃 Proxies&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;确保此配置能不报错生效&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;第 5 歩：重启 ClashX Pro&lt;/h3&gt;</description>
                <pubDate>Mon, 11 Apr 2022 02:39:21 UTC</pubDate>
                <author>1403749842@qq.com (yiqiao)</author>
                <guid>http://yiqiao.me/articles/33/solve-the-problem-that-warp-cannot-be-enabled-after-logging-in-to-github</guid>
                <category>技术之外</category>
            </item>
                    <item>
                <title>解决前后端分离同一域名前端重定向问题</title>
                <link>http://yiqiao.me/articles/32/solve-the-front-end-and-front-end-redirection-problem</link>
                <description>&lt;blockquote&gt;
&lt;p&gt;最近部署服务器的时候发现前后端分离后，需要部署 2 套代码在服务器上，并且还要分配 2 个域名，如果 https 的话还需要 2 个，由于公司的 https 额度不够了，想办法合并一下。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;原本是想在后端代码目录下放前端代码，但是部署后发现，前端重定向页面后被后端的逻辑解析了，所以失败。&lt;/p&gt;
&lt;p&gt;后续请求了群友后发现可以这样：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;部署前端代码收到 /api 开头的请求 就转发。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-nginx&quot;&gt;server{
    listen 80;
    server_name xxx.com;
    ···

    location /api{
        #反代服务器81端口
        proxy_pass http://xxx.xxxx.xxx:81;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Real-IP         $remote_addr;
    }
}
    ···
    #BINDING-后端-START
    server
    {
        listen 81;# 这里的端口要和上面一致
        server_name xxx.com;

        ····
    }
    #BINDING-后端-END&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;TIP：如果以上代码配置不生效，记得服务器端口需要放行，放行后服务器顺便开了。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;使用 telnet 尝试连接
telnet IP 端口&lt;/code&gt;&lt;/pre&gt;</description>
                <pubDate>Mon, 27 Dec 2021 11:00:58 UTC</pubDate>
                <author>1403749842@qq.com (yiqiao)</author>
                <guid>http://yiqiao.me/articles/32/solve-the-front-end-and-front-end-redirection-problem</guid>
                <category>前端</category>
            </item>
                    <item>
                <title>集成 Ngrok 反向代理</title>
                <link>http://yiqiao.me/articles/31/integrated-ngrok-reverse-proxy</link>
                <description>&lt;h3&gt;2025 年 2 月 17 日更新&lt;/h3&gt;
&lt;p&gt;今年我更换了 Docker 版本，因此更新一下&lt;/p&gt;
&lt;h3&gt;创建 docker-compsoe.yaml&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;services:
  ngrok:
    image: ngrok/ngrok:latest
    volumes:
      - ./ngrok.yml:/etc/ngrok.yml
    environment:
      NGROK_AUTHTOKEN: 你的authkey
      NGROK_CONFIG: /etc/ngrok.yml&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;ngrok 配置&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;version: 3
agent:
  web_addr: 0.0.0.0:4040
tunnels:
  example:   #你自定义的管道名称
    proto: http
    addr: https://demo.lcoal/  # 你自定义的域名&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Bug: 这里我遇到一个 无论我 addr 怎么写，始终给我代理的是 nginx 中文件第一个域名，这里我排查了一下设置了 nginx 配置 default_server 就可以了。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;检查好你 &lt;code&gt;nginx&lt;/code&gt; 下边的所有配置 &lt;code&gt;listen&lt;/code&gt; 是否有 &lt;code&gt;default_server&lt;/code&gt;，把他全部删除，直到剩下你需要配置的 &lt;code&gt;nginx&lt;/code&gt; 配置
例如:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;└── conf.d
    ├── domain1.conf
    ├── domain2.conf
    ├── domain3.conf
    └── domain*.conf&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;

&lt;blockquote&gt;
&lt;p&gt;由于开发环境没有外网 IP，支付宝和微信支付的回调无法直接访问到开发环境的接口，了解一下内网穿透神器 Ngrok，来解决此问题。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Ngrok 是一个反向代理软件，启动后会在公共服务器和本地客户端之间建立一个通道，并由公共服务器分配一个唯一的域名给这个通道。在 Homestead 中运行 Ngrok 之后，通过公共服务器分配的域名就可以在公网访问到 Homestead 中的站点，从而让支付宝和微信支付的服务器直接将回调数据发送到对应的回调接口。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;1. 注册 Ngrok 账号&lt;/h3&gt;
&lt;p&gt;Ngrok 官网提供了免费的公共服务器，但需要注册才能使用，访问注册：&lt;a href=&quot;https://dashboard.ngrok.com/signup&quot;&gt;Ngrok 官网&lt;/a&gt;
&lt;img src=&quot;https://pic.imgdb.cn/item/61930d782ab3f51d91637e46.jpg&quot; alt=&quot;ngork&quot; /&gt;&lt;/p&gt;
&lt;p&gt;注册后可以看到以下内容：
&lt;img src=&quot;https://pic.imgdb.cn/item/61930e262ab3f51d9163b105.jpg&quot; alt=&quot;ngork&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;2.配置&lt;/h3&gt;
&lt;p&gt;首先你得去下载 ngrok 集成命令包，下载后解压，来到根目录配置 token。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;./ngrok authtoken 你的token&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3. 启动 Ngrok 客户端&lt;/h3&gt;
&lt;p&gt;2025 年 1 月 4 日更新&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;./ngrok http 你的本地域名
即可启动&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;http&lt;/code&gt; 代表映射协议&lt;/p&gt;
&lt;p&gt;执行成功后访问 &lt;a href=&quot;http://localhost:4040&quot;&gt;http://localhost:4040&lt;/a&gt; 就有 ngrok 管理面板了。&lt;/p&gt;
&lt;h3&gt;Homestead 环境配置&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;ngrok authtoken 你的token

ngrok http 本地域名&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://pic.imgdb.cn/item/619310e62ab3f51d91646971.jpg&quot; alt=&quot;ngrok 配置&quot; /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注意看 Web Interface，地址已经变成 &lt;a href=&quot;http://192.168.10.10:4040&quot;&gt;http://192.168.10.10:4040&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;https://pic.imgdb.cn/item/619311352ab3f51d9164895c.jpg&quot; alt=&quot;ngrok 配置&quot; /&gt;&lt;/p&gt;</description>
                <pubDate>Tue, 16 Nov 2021 02:18:22 UTC</pubDate>
                <author>1403749842@qq.com (yiqiao)</author>
                <guid>http://yiqiao.me/articles/31/integrated-ngrok-reverse-proxy</guid>
                <category>Laravel</category>
            </item>
                    <item>
                <title>Homestead 安装 swoole</title>
                <link>http://yiqiao.me/articles/30/homestead-install-swoole</link>
                <description>&lt;h3&gt;安装&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;安装最新版本：pecl install swoole
安装指定版本：pecl install swoole-4.8.13&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Tip: No releases available for package &quot;pecl.php.net/swoole&quot; 报错执行以下命令&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;pecl channel-update pecl.php.net&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;成功返回&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;Build process completed successfully
Installing &#039;/usr/include/php/20190902/ext/swoole/config.h&#039;
Installing &#039;/usr/lib/php/20190902/swoole.so&#039;
install ok: channel://pecl.php.net/swoole-4.4.13
configuration ⌥ &quot;php_ini&quot; is not set to php.ini location
You should add &quot;extension=swoole.so&quot; to php.ini&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;开启 swoole 扩展&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;查看 php 版本，我这是 7.4  
sudo vi /etc/php/7.4/cli/php.ini 添加上 extension=swoole.so&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;重启配置&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;sudo service php7.4-fpm restart
php --ri swoole 查看是否安装成功&lt;/code&gt;&lt;/pre&gt;</description>
                <pubDate>Thu, 19 Aug 2021 09:07:33 UTC</pubDate>
                <author>1403749842@qq.com (yiqiao)</author>
                <guid>http://yiqiao.me/articles/30/homestead-install-swoole</guid>
                <category>PHP</category>
            </item>
                    <item>
                <title>关于 Homestead 出现 Removing package-versions-deprecated 问题</title>
                <link>http://yiqiao.me/articles/29/the-problem-of-removing-package-versions-deprecated-occurred-in-homestead</link>
                <description>&lt;p&gt;我的环境是 &lt;code&gt;homestead&lt;/code&gt;
安装 Dcat-admin 2.x 版本的时候，发生报错。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-composer&quot;&gt; - Removing composer/package-versions-deprecated 
   Install of composer/package-versions-deprecated failed &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;后来我发现 &lt;code&gt;composer update&lt;/code&gt; 也报错了。后面翻了下资料找到解决方案。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/composer/composer/issues/9361&quot; title=&quot;资料一&quot;&gt;资料一&lt;/a&gt; 和 &lt;a href=&quot;https://github.com/composer/composer/issues/9627&quot; title=&quot;资料二&quot;&gt;资料二&lt;/a&gt; 讨论指出这是 &lt;code&gt;virtualbox&lt;/code&gt; 的问题，特别是 vboxfs 和有关新创建的文件（即解压缩的 zip）未从主机操作系统完全准备好的问题。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ol&gt;&lt;li&gt;在某处创建一个名为 unzip 的脚本。也可能位于您项目的根目录中（composer.json 所在的位置）。如果您的存储速度较慢（例如硬盘），请调整时间，例如 sleep 0.9。&lt;pre&gt;&lt;code&gt;vi unzip
内容：
#!/bin/sh
/usr/bin/unzip &quot;$@&quot;
sleep 0.2&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;2.输入 Vagrant 实例（此步骤之后的所有内容都在其中）：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;vagrant ssh&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;3&quot;&gt;&lt;li&gt;
&lt;p&gt;将脚本复制到 &lt;code&gt;usr/local/bin&lt;/code&gt; 例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo cp /Code/project/unzip /usr/local/bin&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;允许文件可执行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo chmod +x /usr/local/bin/unzip&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;再次执行 &lt;code&gt;composer&lt;/code&gt; 命令&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;</description>
                <pubDate>Fri, 30 Jul 2021 03:27:05 UTC</pubDate>
                <author>1403749842@qq.com (yiqiao)</author>
                <guid>http://yiqiao.me/articles/29/the-problem-of-removing-package-versions-deprecated-occurred-in-homestead</guid>
                <category>Laravel</category>
            </item>
                    <item>
                <title>成功的 Git 分支模型</title>
                <link>http://yiqiao.me/articles/28/successful-git-branching-model</link>
                <description>&lt;p&gt;最近项目开始做大起来了，需要团队协作。由于之前一直是在 master 分支上开发，现在项目新增人手，就需要换个方案了。找了挺多资料的，发现有篇讲的比较全。就转发翻译了一下。&lt;/p&gt;
&lt;p&gt;原文：&lt;a href=&quot;https://nvie.com/posts/a-successful-git-branching-model/&quot;&gt;A successful Git branching model&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;反思笔记（2020年3月5日）&lt;/p&gt;
&lt;p&gt;这个模型是在 2010 年构思出来的，而现在距今已有 10 多年的历史，而 Git 本身才诞生不久。在那 10 年中，git-flow「本文介绍的分支模型」在许多软件团队中非常流行，以至于人们开始将其视为某种标准，但不幸的是，它也被当作教条或灵丹妙药。&lt;/p&gt;
&lt;p&gt;在那 10 年中，Git 本身就席卷了整个世界，并且与 Git 一起开发的最流行的软件类型正在越来越多地转向 Web 应用程序-至少在我的过滤泡中。 Web 应用程序通常是连续交付的，不会回滚，并且您不必支持在野外运行的软件的多个版本。&lt;/p&gt;
&lt;p&gt;这不是我十年前写博客时想到的那种软件。如果您的团队正在持续交付软件，我建议您采用更简单的工作流程「例如 &lt;a href=&quot;https://guides.github.com/introduction/flow/&quot;&gt;GitHub Flow&lt;/a&gt;」，而不是尝试将 git-flow 引入您的团队。&lt;/p&gt;
&lt;p&gt;但是，如果您正在构建显式版本的软件，或者如果您需要狂野地支持软件的多个版本，那么git-flow 仍然可能像适合您团队的人一样适合您的团队最近 10 年。在这种情况下，请继续阅读。&lt;/p&gt;
&lt;p&gt;总而言之，请始终记住万灵药不存在。考虑您自己的情况。别讨厌自己决定。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在这篇文章中，我介绍了大约一年前我为我的一些项目「在工作中和在私人项目中」引入的开发模型，事实证明该模型非常成功。我一直想写一阵子，但是直到现在为止我还没有真正找到时间这样做。我不会谈论任何项目的详细信息，而只会谈论分支策略和发布管理。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://nvie.com/img/git-model@2x.png&quot; alt=&quot;大图&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;为什么是 git？&lt;/h2&gt;
&lt;p&gt;有关 Git 与集中式源代码控制系统相比的优缺点的详尽讨论，请参见 &lt;a href=&quot;https://git.wiki.kernel.org/index.php/GitSvnComparsion&quot;&gt;Web&lt;/a&gt;。那里发生了许多火焰大战。作为开发人员，我比今天所有其他工具都更喜欢Git。 Git 确实改变了开发人员对合并和分支的看法。在我来自经典的CVS / Subversion 的世界中，合并/分支一直被认为有点吓人「当心合并冲突，它们会伤害你！」，而您却偶尔会做一次。&lt;/p&gt;
&lt;p&gt;但是，使用Git，这些操作非常容易且简单，实际上，它们被视为日常工作流程的核心部分之一。例如，在CVS / Subversion &lt;a href=&quot;http://svnbook.red-bean.com/&quot;&gt;书籍&lt;/a&gt;中，分支和合并首先在后面的章节中（针对高级用户）进行讨论，而在每本&lt;a href=&quot;https://github.com/progit/progit&quot;&gt; Git 书籍&lt;/a&gt;中，第3章（基础知识）都已经进行了介绍。&lt;/p&gt;
&lt;p&gt;由于其简单性和重复性，分支和合并不再是令人害怕的事情。版本控制工具应该比其他任何工具都更有助于分支/合并。&lt;/p&gt;
&lt;p&gt;有关这些工具的足够多的知识，让我们进入开发模型。我将在此处介绍的模型本质上不过是每个团队成员必须遵循的一组程序才能进入托管软件开发过程。&lt;/p&gt;
&lt;h2&gt;分散但集中&lt;/h2&gt;
&lt;p&gt;我们使用的存储库设置与该分支模型一起很好地使用，它是一个中央「真实」存储库。请注意，此存储库仅被视为中央存储库「由于 Git 是 DVCS，因此在技术层面上没有中央存储库之类的东西」。我们将此仓库称为起源，因为所有 Git 用户都熟悉该名称。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://nvie.com/img/centr-decentr@2x.png&quot; alt=&quot;git&quot; /&gt;&lt;/p&gt;
&lt;p&gt;每个开发人员都拉起并推到原点。但是，除了集中的推拉关系之外，每个开发人员还可以从其他同伴那里拉出变更以组成子团队。例如，在将进行中的工作过早地推向市场之前，与两个或多个开发人员一起使用一项重大的新功能可能会很有用。在上图中，有 Alice 和 Bob，Alice 和David 以及 Clair 和 David 的子团队。&lt;/p&gt;
&lt;p&gt;从技术上讲，这仅意味着 Alice 定义了一个名为 bob 的 Git 遥控器，该遥控器指向 Bob 的存储库，反之亦然。&lt;/p&gt;
&lt;h2&gt;主要分支&lt;/h2&gt;&lt;p&gt;
&lt;img width=&quot;267&quot; src=&quot;https://nvie.com/img/main-branches@2x.png&quot; alt=&quot;main-branches@2x.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;从根本上说，开发模型受到了现有模型的极大启发。中央存储库包含两个无限生命的主要分支：&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;master&lt;/li&gt;
&lt;li&gt;develop&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;每个 Git 用户都应该熟悉原始的 master 分支。与 master 分支平行，存在另一个分支称为develop。&lt;/p&gt;
&lt;p&gt;我们认为 origin/develop 是 HEAD 源代码始终反映状态的主要分支，该状态具有下一发行版的最新交付开发更改。有人将其称为「整合分支」。这是构建任何夜间自动构建的地方。&lt;/p&gt;
&lt;p&gt;当 develop 分支中的源代码达到稳定点并准备发布时，所有更改应以某种方式合并回 master，然后用发布号标记。如何进行详细的讨论将在后面进行讨论。&lt;/p&gt;
&lt;p&gt;因此，每次将更改合并回主版本时，根据定义，这是一个新的生产版本。我们通常对此非常严格，因此从理论上讲，每当主服务器上有提交时，我们就可以使用 Git 钩子脚本自动将软件构建和推出到生产服务器。&lt;/p&gt;
&lt;h2&gt;分支行&lt;/h2&gt;
&lt;p&gt;除了主要分支机构的掌握和开发之外，我们的开发模型还使用各种支持分支机构，以帮助团队成员之间进行并行开发，简化功能跟踪，为生产发布做准备并协助快速解决生产中的实际问题。与主要分支不同，这些分支的生命周期总是有限的，因为它们最终将被删除。&lt;/p&gt;
&lt;p&gt;我们可以使用的不同类型的分支机构是：&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;功能分支&lt;/li&gt;
&lt;li&gt;发布分支&lt;/li&gt;
&lt;li&gt;修补程序分支&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;这些分支中的每一个都有特定的用途，并受严格的规则约束，即哪些分支可能是其原始分支，哪些分支必须是其合并目标。我们将在一分钟内逐步解决它们。&lt;/p&gt;
&lt;p&gt;从技术的角度来看，这些分支绝不是「特殊的」。分支类型是根据我们的使用方式进行分类的。它们当然是普通的旧 Git 分支。&lt;/p&gt;
&lt;h3&gt;功能分支&lt;/h3&gt;&lt;p&gt;
&lt;img width=&quot;133&quot; src=&quot;https://nvie.com/img/fb@2x.png&quot; alt=&quot;fb@2x.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;可能从以下分支：
  develop
必须合并回：
  develop
分支命名约定：
  除了master，develop，release- &lt;em&gt; 或 hotfix- &lt;/em&gt; 以外的任何东西&lt;/p&gt;
&lt;p&gt;功能分支「或有时称为主题分支」用于为即将发布或遥远的将来版本开发新功能。当开始开发功能时，此时可能不知道将合并该功能的目标版本。功能分支的本质是只要功能在开发中就存在，但是最终会合并回到开发中「以确保将新功能添加到即将发布的版本中」或丢弃「以防实验令人失望」。
功能分支通常仅存在于开发人员存储库中，而不存在于源中。&lt;/p&gt;
&lt;h4&gt;创建功能分支&lt;/h4&gt;
&lt;p&gt;当开始使用新功能时，请从 develop 分支中分支出来。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-git&quot;&gt;$ git checkout -b myfeature develop
切换到新的分支 「myfeature」&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;在开发中加入完成的功能&lt;/h4&gt;
&lt;p&gt;可以将完成的功能合并到 developer 分支中，以确保将它们添加到即将发布的版本中：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-git&quot;&gt;$ git checkout develop
切换到分支 「develop」
$ git merge --no-ff myfeature
更新 ea1b82a..05e9557 「变更摘要」
$ git branch -d myfeature
已删除分支 myfeature「之前是05e9557」
$ git push origin develop&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;--no-ff 标志使合并始终创建一个新的提交对象，即使合并可以通过快进来执行。这样可以避免丢失有关要素分支历史存在的信息，并将所有添加了要素的提交分组在一起。比较：
&lt;img src=&quot;https://nvie.com/img/merge-without-ff@2x.png&quot; alt=&quot;比较图片&quot; /&gt;
在后一种情况下，无法从 Git 历史记录中看到哪些提交对象一起实现了功能—您将不得不手动读取所有日志消息。在后一种情况下，还原整个功能「即一组提交」确实很头疼，而如果使用 --no-ff 标志则很容易做到。&lt;/p&gt;
&lt;p&gt;是的，它将创建更多「空」提交对象，但收益远大于成本。&lt;/p&gt;
&lt;h3&gt;发布分支&lt;/h3&gt;
&lt;p&gt;可能从以下分支：
  develop
必须合并回：
  develop 和 master
分支命名约定：
  release-*&lt;/p&gt;
&lt;p&gt;发布分支支持新产品版本的准备。他们允许最后一刻对细节一丝不苟。此外，它们允许进行较小的错误修复并为发布准备元数据「版本号，构建日期等」。通过在发行分支上完成所有这些工作，将清除 develop 分支以接收下一个大型发行版的功能。&lt;/p&gt;
&lt;p&gt;从 develop 分支出新版本分支的关键时刻是 develop「几乎」何时反映新版本的所需状态。此时至少必须合并要构建的发行版的所有功能。面向将来发行版的所有功能可能都不会—它们必须等到发行分支分支出来之后。&lt;/p&gt;
&lt;p&gt;正是在发行分支的开头，为即将发布的版本分配了版本号-较早的版本。直到那一刻，develop 分支都反映了「下一个发行版」的更改，但是尚不清楚该「下一个发行版」最终将变为 0.3 还是1.0，直到发行分支开始。该决定是在发布分支的开始时做出的，并且由项目的版本号增加规则来执行。&lt;/p&gt;
&lt;h4&gt;创建一个发布分支&lt;/h4&gt;
&lt;p&gt;发布分支是从开发分支创建的。例如，说版本 1.1.5 是当前的生产版本，我们即将发布一个大版本。开发状态已准备就绪，可用于「下一个发行版」，我们已经决定将其变成 1.2 版「而不是1.1.6或2.0版」。因此，我们分支并给发行分支起一个反映新版本号的名称：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-git&quot;&gt;$ git checkout -b release-1.2 develop
选择一个新分支 「release-1.2」
$ ./bump-version.sh 1.2
文件修改成功，版本升至1.2。
$ git commit -a -m &quot;将版本提高至 1.2&quot;
[release-1.2 74d9424] 将版本号推送到 1.2
1 files changed, 1 insertions(+), 1 deletions(-)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;创建新分支并切换到该分支后，我们更改版本号。在这里，bump-version.sh 是一个虚构的shell 脚本，它会更改工作副本中的某些文件以反映新版本。 「当然，这可以是手动更改-关键是某些文件会更改。」然后，提交被修改的版本号。&lt;/p&gt;
&lt;p&gt;这个新分支可能在那里存在了一段时间，直到可以肯定地发布该版本为止。在此期间，错误修复程序可能会应用于此分支「而不是develop分支」。严格禁止在此处添加大型新功能。必须将它们合并到开发中，因此，请等待下一个重要版本。&lt;/p&gt;
&lt;h4&gt;完成发布分支&lt;/h4&gt;
&lt;p&gt;当发布分支的状态准备好成为真实发布时，需要执行一些操作。首先，将release分支合并到master中「记住，由于 master 上的每次提交都是新的发行，请记住」。接下来，必须标记对主提交的提交，以便将来轻松参考此历史版本。最后，需要将对发行分支所做的更改重新合并到开发中，以便将来的发行版也包含这些错误修复程序。&lt;/p&gt;
&lt;p&gt;Git 的前两个步骤：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-git&quot;&gt;$ git checkout master
切换到 &#039;master&#039;
$ git merge --no-ff release-1.2
递归合并「更改摘要」
$ git tag -a 1.2&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;该版本现已完成，并已标记以供将来参考。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;编辑：您也可能希望使用-s或-u 标志以加密方式对标签进行签名。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;为了保留在 release 分支中所做的更改，我们需要将这些更改重新合并到 develop 中。在Git中：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-git&quot;&gt;$ git checkout develop
切换 &#039;develop&#039;
$ git merge --no-ff release-1.2
递归合并「更改摘要」&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;此步骤很可能导致合并冲突「因为我们已经更改了版本号」。如果是这样，请修复它并提交。
现在我们已经完成了，并且释放分支可能已删除，因为我们不再需要它了：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ git branch -d release-1.2
删除了分支版本1.2「为 ff452fe」&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;修补程序分支&lt;/h3&gt;&lt;p&gt;
&lt;img width=&quot;316&quot; src=&quot;https://nvie.com/img/hotfix-branches@2x.png&quot; alt=&quot;hotfix-branches@2x.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;可能从以下分支：
  master
必须合并回：
  develop 和 master
分支命名约定：
  hotfix-*&lt;/p&gt;
&lt;p&gt;修补程序分支与发布分支非常相似，尽管它们是计划外的，但它们也旨在为新的生产版本做准备。它们源于对不期望的实时生产版本立即采取行动的必要性。当必须立即解决生产版本中的严重错误时，可以从标记生产版本的 master 分支上的相应标记中分支出一个修补程序分支。&lt;/p&gt;
&lt;p&gt;实质是团队成员的工作（在 develop 分支）可以继续，而另一个人正在准备快速的生产修复。&lt;/p&gt;
&lt;h4&gt;创建修补程序分支&lt;/h4&gt;
&lt;p&gt;修补程序分支是从 master 分支创建的。例如，说 1.2 版是当前的生产版本，正在运行，并且由于严重的错误而引起麻烦。但是发展的变化还不稳定。然后，我们可能会分支出一个修补程序分支并开始解决问题：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-git&quot;&gt;$ git checkout -b hotfix-1.2.1 master
切换到新的分支 「hotfix-1.2.1」
$ ./bump-version.sh 1.2.1
文件修改成功，版本升至1.2.1。
$ git commit -a -m &quot;Bumped version number to 1.2.1&quot;
[hotfix-1.2.1 41e61bb] 将版本号推送到1.2.1
1 files changed, 1 insertions(+), 1 deletions(-)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;别忘了在分支后增加版本号！&lt;/p&gt;
&lt;p&gt;然后，修复该错误，并在一个或多个单独的提交中提交此修复程序。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-git&quot;&gt;$ git commit -m &quot;Fixed severe production problem&quot;
[hotfix-1.2.1 abbe5d6] 解决了严重的生产问题
5 files changed, 32 insertions(+), 17 deletions(-)&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;完成修补程序分支&lt;/h4&gt;
&lt;p&gt;完成后，该错误修复程序需要重新合并到母版中，但也需要重新合并到开发中，以保护该错误修复程序也包含在下一个版本中。这与释放分支的完成方式完全相似。&lt;/p&gt;
&lt;p&gt;首先，更新 master 并标记发行版。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-git&quot;&gt;$ git checkout master
切换到 &#039;master&#039;
$ git merge --no-ff hotfix-1.2.1
递归合并「更改摘要」
$ git tag -a 1.2.1&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;编辑：您也可能希望使用-s或-u 标志以加密方式对标签进行签名。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;接下来，在 develop 分支中也包含错误修正：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-git&quot;&gt;$ git checkout develop
切换到 &#039;develop&#039;
$ git merge --no-ff hotfix-1.2.1
递归合并「更改摘要」&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;该规则的一个例外是，当当前存在发行分支时，需要将修补程序更改合并到该发行分支中，而不是进行开发。在发行分支完成后，将错误修正回合并到发行分支中，最终也会导致该修正修正也被合并到开发中。 「如果开发人员中的工作立即需要此错误修复，而不能等待发布分支完成，则现在也可以安全地将错误修复合并到开发中。」&lt;/p&gt;
&lt;p&gt;最后，删除临时分支：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ git branch -d hotfix-1.2.1
删除了分支修补程序 1.2.1「为 abbe5d6」&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;总结&lt;/h3&gt;
&lt;p&gt;尽管该分支模型没有什么真正令人震惊的新东西，但这篇文章开头的「大图」图在我们的项目中被证明是非常有用的。它形成了一个易于理解的优雅思维模型，并允许团队成员对分支和发布过程形成共识。&lt;/p&gt;</description>
                <pubDate>Fri, 30 Jul 2021 03:00:03 UTC</pubDate>
                <author>1403749842@qq.com (yiqiao)</author>
                <guid>http://yiqiao.me/articles/28/successful-git-branching-model</guid>
                <category>技术之外</category>
            </item>
                    <item>
                <title>使用 Docker 快速部署 Rasa</title>
                <link>http://yiqiao.me/articles/27/rapid-deployment-of-rasa-using-docker</link>
                <description>&lt;blockquote&gt;
&lt;p&gt;最近有个项目需要分析用户说出的话对应的相关结果。原本用结巴分词一个一个去匹配，后来数据越来越大，这样就得找其他方案了。后来了解 到 NLP，而且有个开源的项目 Rasa。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;国内资源还是很少，官方的中文文档没人翻译，都要自己去看英文，便把这次部署记录下来。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;PS : 本次部署是在 Docker 上，需要安装 Docker 后才可以进行后续操作。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;创建项目&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mkdir ~/rasa &amp;amp;&amp;amp; cd rasa
docker run -v ~/rasa:/app rasa/rasa init --no-prompt&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;使用Docker训练自定义Rasa模型&lt;/h3&gt;
&lt;p&gt;编辑 &lt;code&gt;config.yml&lt;/code&gt; 文件以使用所需的管道，并将 NLU 和 Core 数据放入 data/ 目录中。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;docker run -v ~/rasa:/app rasa/rasa:latest-full train --domain domain.yml --data data --out models&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;运行 Rasa 服务&lt;/h3&gt;
&lt;p&gt;要在生产中运行 AI 助手，请在 &lt;code&gt;credentials.yml&lt;/code&gt; 中配置所需的消息和语音通道。如果此文件不存在，请使用以下命令创建:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;touch credentials.yml&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后根据你连接的通道进行编辑。之后，运行训练模型:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;docker run -v ~/rasa/models:/app/models rasa/rasa:latest-full run&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;使用 Docker Compose 运行多个服务:&lt;/h3&gt;
&lt;p&gt;创建 &lt;code&gt;docker-compose.yml&lt;/code&gt; 文件：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-docker&quot;&gt;touch docker-compose.yml
添加以下内容：
version: &#039;3.0&#039;
services:
  rasa:
    image: rasa/rasa:latest-full
    ports:
      - 5005:5005
    volumes:
      - ./:/app
    command:
      - run&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;运行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker-compose up 
挂载后台
docker-compose up -d&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;运行成功后访问 &lt;a href=&quot;http://localhost:5005&quot;&gt;localhost:5005&lt;/a&gt; 即可。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;测试请求&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;curl -X POST \
  http://localhost:5005/model/parse \
  -d &#039;{
    &quot;text&quot;: &quot;Hello!&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;PS: 若需要鉴权验证则需要添加一下，修改 docker-compose.yml，这里有 &lt;code&gt;token&lt;/code&gt; 密钥和 &lt;code&gt;jwt&lt;/code&gt;，这里我选择了 &lt;code&gt;auth-token&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code class=&quot;language-docker&quot;&gt;***
command:
      - run 
      - -m models
      - --enable-api
      - --auth-token 
      - 你的密码&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;curl -X POST \
  http://localhost:5005/model/parse?token=你的密码 \
  -d &#039;{
    &quot;text&quot;: &quot;Hello!&quot;
}&lt;/code&gt;&lt;/pre&gt;</description>
                <pubDate>Fri, 19 Mar 2021 02:44:35 UTC</pubDate>
                <author>1403749842@qq.com (yiqiao)</author>
                <guid>http://yiqiao.me/articles/27/rapid-deployment-of-rasa-using-docker</guid>
                <category>AI</category>
            </item>
                    <item>
                <title>GitHub 访问提速</title>
                <link>http://yiqiao.me/articles/26/speed-up-github-access</link>
                <description>&lt;blockquote&gt;
&lt;p&gt;最近不知道怎么回事，GitHub 无法访问，必须开代理全局访问。但这样有时候在终端无法拉取代码。这样就得调整下。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;1.获取 GitHub 官方 CDN 地址&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.ipaddress.com/&quot;&gt;访问这个网址&lt;/a&gt;，去获取查询以下三个链接的 DNS 解析地址&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;github.com&lt;/li&gt;
&lt;li&gt;assets-cdn.github.com&lt;/li&gt;
&lt;li&gt;github.global.ssl.fastly.net&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;例如：&lt;img src=&quot;https://pic.imgdb.cn/item/6049f2555aedab222c09862e.jpg&quot; alt=&quot;案例&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;2.修改 hosts 文件&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;以我的 MacBook 为例：
vi ~/etc/hosts
把刚才的 ip 地址改上去，例如：
199.232.69.194 github.global.ssl.fastly.net
140.82.113.3 github.com
185.199.109.153 assets-cdn.Github.com&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;保存后，刷新即可，若没生效，重启电脑试试。&lt;/p&gt;</description>
                <pubDate>Thu, 11 Mar 2021 10:37:39 UTC</pubDate>
                <author>1403749842@qq.com (yiqiao)</author>
                <guid>http://yiqiao.me/articles/26/speed-up-github-access</guid>
                <category>技术之外</category>
            </item>
                    <item>
                <title>MacApp 常见问题</title>
                <link>http://yiqiao.me/articles/25/macapp-chang-jian-wen-ti</link>
                <description>&lt;h2&gt;收集一些下载应用可能出现的问题&lt;/h2&gt;
&lt;h3&gt;下载好的DMG 打不开&lt;/h3&gt;
&lt;h4&gt;1.提示：&lt;code&gt;image not recognized&lt;/code&gt;&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;这个说明下载不完整，重新下载&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;2. 提示：xxx.app已损坏,打不开.你应该将它移到废纸篓&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;1.打开终端&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;2.&lt;code&gt;sudo xattr -d com.apple.quarantine /Applications/xxxx.app&lt;/code&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注意：&lt;code&gt;/Applications/xxxx.app&lt;/code&gt; 换成你的App路径（推荐直接将 .app 文件拖入终端中自动生成路径，以防空格等转义字符手动复制或输入出现错误）&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;3.重启 App 即可&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;3.提示「打不开 xxx，因为它来自身份不明的开发者」&lt;/h4&gt;
&lt;p&gt;出现这个问题的解决方法有2种：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;1.按住 &lt;code&gt;Control&lt;/code&gt; 后，再次点击软件图标，即可。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;2.修改系统配置：系统偏好设置... -&amp;gt; 安全性与隐私。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;修改为任何来源&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;如图所示：
&lt;img src=&quot;https://pic.imgdb.cn/item/5edf5a79c2a9a83be5e19e90.png&quot; alt=&quot;修改配置&quot; /&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/blockquote&gt;
&lt;h3&gt;重要事项：如果没有这个选项的话，去终端输入 &lt;code&gt;sudo spctl --master-disable&lt;/code&gt; 回车后输入密码后，再次重复刚才步骤，就会出现任何来源了。&lt;/h3&gt;
&lt;h4&gt;4. TNT 和谐软件闪退问题&lt;/h4&gt;
&lt;blockquote&gt;
&lt;ol&gt;&lt;li&gt;安装 X-code「在 App Store」下载即可。「8G多」&lt;/li&gt;
&lt;/ol&gt;&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;2.安装Command Line Tools 工具&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;打开终端工具输入如下命令：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;xcode-select --install&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;3.签名&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;codesign --force --deep --sign - /Applications/xxx.app

注意后面的文件路径，你可以打开访达找到应用程序，找到要签名的软件，直接拖入终端界面，即可自动生成路径。&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;成功后回返回以下结果：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;replacing existing signature&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;如果以上问题完成后还是无法运行，尝试关闭一下SIP。&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;1.关机，然后重新启动你的Mac电脑，在开机时一直按住&lt;code&gt;Command+R迸入Recovery&lt;/code&gt; 模式。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;2.进入 Recovery 模式后打开终端。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;img src=&quot;https://pic.imgdb.cn/item/5edf5e0ac2a9a83be5e68f07.jpg&quot; alt=&quot;Recovery 模式&quot; /&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;ol start=&quot;3&quot;&gt;&lt;li&gt;在终端上输入命令 &lt;code&gt;csrutil disable&lt;/code&gt; 然后回车。&lt;/li&gt;
&lt;/ol&gt;&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;ol start=&quot;4&quot;&gt;&lt;li&gt;重启设备。&lt;/li&gt;
&lt;/ol&gt;&lt;/blockquote&gt;</description>
                <pubDate>Tue, 09 Jun 2020 09:38:00 UTC</pubDate>
                <author>1403749842@qq.com (yiqiao)</author>
                <guid>http://yiqiao.me/articles/25/macapp-chang-jian-wen-ti</guid>
                <category>MacAppCloud</category>
            </item>
                    <item>
                <title>Nginx 配置二级域名</title>
                <link>http://yiqiao.me/articles/24/nginx-pei-zhi-er-ji-yu-ming</link>
                <description>&lt;p&gt;最近写了个 demo，需要二级域名来显示，便记录下来&lt;/p&gt;
&lt;h3&gt;域名服务器&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;我的域名用了 CDN，所以得去 CDN 那边配置，例如「cloudflare」&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;记录类型 &lt;code&gt;CNAME&lt;/code&gt;，名称 &lt;code&gt;你的二级域名名称「book」&lt;/code&gt;，   内容 &lt;code&gt;你的域名「yiqiao.me」&lt;/code&gt;, 配置后 ping 下是否可以通。&lt;/p&gt;
&lt;h3&gt;Nginx 配置&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;修改 Nginx 配置，以 default 文件为例&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;sudo vi /etc/nginx/sites-available/default&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;由于我的项目是 &lt;code&gt;Laravel&lt;/code&gt; 框架写的，所以我的配置文件如下：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;server {
    listen 80;
    server_name yiqiao.me;
    root 你的项目路径/public;
    index index.php index.html index.htm;
    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }
    location ~ \.php$ {
      try_files $uri /index.php =404;
      fastcgi_split_path_info ^(.+\.php)(/.+)$;
      fastcgi_pass unix:/run/php/php7.2-fpm.sock;
      fastcgi_index index.php;
      fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
      include fastcgi_params;
    }
}

server {
    listen 80;
    server_name book.yiqiao.me;
    root 你的项目路径/public;
    index index.php index.html index.htm;
    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }
    location ~ \.php$ {
      try_files $uri /index.php =404;
      fastcgi_split_path_info ^(.+\.php)(/.+)$;
      fastcgi_pass unix:/run/php/php7.2-fpm.sock;
      fastcgi_index index.php;
      fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
      include fastcgi_params;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;配置后 &lt;code&gt;nginx -t&lt;/code&gt;，检查下 NGINX 配置是否写对，无误后重启 &lt;code&gt;service nginx reload&lt;/code&gt;&lt;/p&gt;</description>
                <pubDate>Mon, 27 Apr 2020 03:01:55 UTC</pubDate>
                <author>1403749842@qq.com (yiqiao)</author>
                <guid>http://yiqiao.me/articles/24/nginx-pei-zhi-er-ji-yu-ming</guid>
                <category>Http 服务器</category>
            </item>
                    <item>
                <title>终端翻墙备忘录</title>
                <link>http://yiqiao.me/articles/23/zhong-duan-fan-qiang-bei-wang-lu</link>
                <description>&lt;p&gt;最近换了新电脑，由于某些原因需要用命令行下载国外资源，但是发现电脑是开了代理的，但是终端没有效果，添加以下配置即可生效：
我使用的代理软件是：「Shadowsocks-X」，可以在「HTTP 代理设置」 查看端口，我的端口是 1087&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;在 &lt;code&gt;~/.bash_profile&lt;/code&gt; 文件夹填写以下配置：&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;export http_proxy=http://127.0.0.1:1087
export https_proxy=$http_proxy&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;让配置立即生效:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;source ~/.bash_profile&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看是否启用&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;env | grep -i proxy&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看终端代理 ip 地址：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;curl ip.cn
若无效使用
curl cip.cc&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以显示 「IP」，「地址」都已经是代理 IP 了&lt;/p&gt;</description>
                <pubDate>Thu, 19 Mar 2020 04:02:23 UTC</pubDate>
                <author>1403749842@qq.com (yiqiao)</author>
                <guid>http://yiqiao.me/articles/23/zhong-duan-fan-qiang-bei-wang-lu</guid>
                <category>Linux</category>
            </item>
                    <item>
                <title>Ubuntu 16.04 升级 PHP</title>
                <link>http://yiqiao.me/articles/22/ubuntu-1604-upgrade-php</link>
                <description>&lt;blockquote&gt;
&lt;p&gt;第三版 Blog 终于写好一半了！由于更换了 &lt;code&gt;Laravel 6.*&lt;/code&gt; ，需要换 PHP 版本，于是就记录一下。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;卸载&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;更换 PHP 版本得先删除原来的版本&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;删除php的相关包及配置&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-shelll&quot;&gt;   sudo apt-get autoremove php7*&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;删除关联&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;    sudo find /etc -name &quot;*php*&quot; |xargs  rm -rf &lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;清除dept列表&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;sudo apt purge `dpkg -l | grep php| awk &#039;{print $2}&#039; |tr &quot;\n&quot; &quot; &quot;`&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;检查是否卸载干净&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;dpkg -l | grep php
无返回就是卸载完成&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;安装&lt;/h3&gt;
&lt;h4&gt;添加存储库&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;sudo add-apt-repository ppa:ondrej/php&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;添加 PPA 后更新软件包&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;sudo apt update&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;安装 php7.2 和一些我们需要的重要模块。&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;sudo apt-get install php7.2-cli php7.2-fpm php7.2-curl php7.2-gd php7.2-mysql php7.2-mbstring php7.2-xml zip unzip&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;安装完成后输入 &lt;code&gt;php -v&lt;/code&gt; 即可。&lt;/p&gt;
&lt;h4&gt;启用&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;    service php7.2-fpm start&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;提示
升级了 PHP 版本 ，Nginx 也不要忘记修改。例如:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;location ~ \.php$ {
#       # With php-fpm (or other unix sockets):
fastcgi_pass unix:/run/php/php7.2-fpm.sock;
#       # With php-cgi (or other tcp sockets):
#       fastcgi_pass 127.0.0.1:9000;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;h3&gt;重启 Nginx&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;    service nginx restart&lt;/code&gt;&lt;/pre&gt;</description>
                <pubDate>Thu, 16 Jan 2020 18:40:42 UTC</pubDate>
                <author>1403749842@qq.com (yiqiao)</author>
                <guid>http://yiqiao.me/articles/22/ubuntu-1604-upgrade-php</guid>
                <category>Linux</category>
            </item>
                    <item>
                <title>「手动顶置」本站公告</title>
                <link>http://yiqiao.me/articles/21/manual-overhead-announcement</link>
                <description>&lt;h3&gt;顶置公告&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;很久没有更新 Blog，没想到我的 Blog 还有些人看。还是很开心的。还发现有人注册了本站用户，可惜的是由于网站服务器放在国外，国内邮件服务器没法用。对此先说抱歉啦。最近要考试所以没怎么更新 Blog，我争取年底把第三版 Blog 改出来吧~&lt;/p&gt;
&lt;/blockquote&gt;</description>
                <pubDate>Wed, 16 Oct 2019 12:10:13 UTC</pubDate>
                <author>1403749842@qq.com (yiqiao)</author>
                <guid>http://yiqiao.me/articles/21/manual-overhead-announcement</guid>
                <category>技术之外</category>
            </item>
                    <item>
                <title>PhpStorm 2019.2 最新激活</title>
                <link>http://yiqiao.me/articles/20/latest-activation-of-phpstorm-20192</link>
                <description>&lt;blockquote&gt;
&lt;p&gt;由于之前使用的 IDEA 破解已失效，现在改用破解包激活。
&lt;br /&gt;
他们家的所有产品升级到 &lt;strong&gt;2018.2.1&lt;/strong&gt; 及以上版本后，先前可用的注册服务器都失效了，无法激活升级到最新版本体验最新黑科技。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;目前支持的版本如下：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;IntelliJ IDEA 2019.3.3激活、AppCode 2019.3.5激活、CLion 2019.3.4激活、DataGrip 2019.3.3激活、
GoLand 2019.3.3激活、PhpStorm 2019.3.3激活、PyCharm 2019.3.3激活、Rider 2019.3.4激活、RubyMine 2019.3.3激活、
WebStorm 2019.3.3激活&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;只是该种方式激活稍微有点麻烦，具体步骤如下。&lt;/p&gt;
&lt;h2&gt;破解步骤&lt;/h2&gt;
&lt;h3&gt;1.下载破解包&lt;/h3&gt;
&lt;p&gt;&lt;del&gt;下载地址: &lt;a href=&quot;https://sn9.us/file/15082937-402613392&quot;&gt;jetbrains-agent.jar&lt;/a&gt;&lt;/del&gt;
&lt;del&gt;下载地址：&lt;a href=&quot;https://t00y.com/file/15082937-430482781&quot;&gt;最新 2020.3&lt;/a&gt;&lt;/del&gt;
下载地址：&lt;a href=&quot;https://t00y.com/file/15082937-442885323&quot;&gt;最新 2020.5&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;2.打开 Phpstorm&lt;/h3&gt;
&lt;p&gt;现在一启动需要立刻输入注册码，这里可以选择免费试用的方式进入IDEA，如下图所示。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ae01.alicdn.com/kf/H8fc5fecb0ca441549a9060270844a719q.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;3.编辑 vmoptions&lt;/h3&gt;
&lt;h4&gt;方法一&lt;/h4&gt;
&lt;ul&gt;&lt;li&gt;新用户直接把 &lt;code&gt;jetbrains-agent.jar&lt;/code&gt; 文件拖入 IDE 中安装即可，需要填激活码就在 &lt;code&gt;激活码.txt&lt;/code&gt; 中拿就可以了&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;方法二&lt;/h4&gt;
&lt;p&gt;编辑 vmoptions 文件，在菜单栏点击 Help -&amp;gt; Edit Custom VM Options，进行编辑相关配置文件。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ae01.alicdn.com/kf/H09872f43ecd246a1bc6ec2214bdae293N.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;在打开的 vmoptions 编辑窗末尾添加：&lt;/p&gt;
&lt;p&gt;示例:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;Mac: -javaagent:/你放破解文件的绝对路径/jetbrains-agent.jar
Linux: -javaagent:/你放破解文件的绝对路径/jetbrains-agent.jar
windows: -javaagent:D:/jetbrains-agent.jar&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;这里一定要写好路径，写好路径，写好路径，不然是打不开IDEA的！！！&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;若打不开只能去手动修改，由于我是用 MacOS，下面将 MacOS 下修改，其他平台的自行搜索修改 vmoptions 配置&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;cd ~/Library/Preferences/PhpStorm2019.2
vim phpstorm.vmoptions&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;填写激活码&lt;/h2&gt;
&lt;p&gt;修改好配置，并且能显示 IDE 界面后，在菜单栏点击 Help -&amp;gt; Register 填写注册码。&lt;/p&gt;
&lt;p&gt;注册码在破解文件里面 &lt;code&gt;激活码.txt&lt;/code&gt; 文件。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;注意：如果激活窗口弹出错误（error 1653219），
请去 hosts 文件移除 jetbrains 相关的配置项。


如果注册码的方式不行，可以试试通过 License server 方式来激活，
地址填入：`http://fls.jetbrains-agent.com`（应该会自动填上），
或者点击按钮：「Discover Server 」来自动填充地址，完成激活。&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;以上步骤操作完成后激活就结束了！&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;本项目只做个人学习研究之用，不得用于商业用途！&lt;br /&gt;
若资金允许，请点击&lt;a href=&quot;https://www.jetbrains.com/idea/buy/&quot;&gt;「链接」&lt;/a&gt;购买正版，谢谢合作！&lt;br /&gt;
学生凭学生证可&lt;a href=&quot;https://sales.jetbrains.com/hc/zh-cn/articles/207154369-%E5%AD%A6%E7%94%9F%E6%8E%88%E6%9D%83%E7%94%B3%E8%AF%B7%E6%96%B9%E5%BC%8F&quot;&gt;「免费申请」&lt;/a&gt;正版授权！&lt;br /&gt;
创业公司可&lt;a href=&quot;https://www.jetbrains.com/shop/eform/startup&quot;&gt;「5折购买」&lt;/a&gt;正版授权！&lt;/p&gt;
&lt;/blockquote&gt;</description>
                <pubDate>Mon, 14 Oct 2019 12:20:29 UTC</pubDate>
                <author>1403749842@qq.com (yiqiao)</author>
                <guid>http://yiqiao.me/articles/20/latest-activation-of-phpstorm-20192</guid>
                <category>PHPStorm</category>
            </item>
                    <item>
                <title>记一次 Apache 端口转发代理</title>
                <link>http://yiqiao.me/articles/19/record-an-apache-port-forwarding-agent</link>
                <description>&lt;blockquote&gt;
&lt;p&gt;最近在做微信公众号，由于代码是在本地，而微信公众平台需要线上网站，所以就需要把代码放到公网上面执行。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我的老大帮我分配了个子域名映射到了我的 ip 上，这个只是了解到了他用的是 frp。
而我本机只是用了代理转发。以下是我的代码&lt;/p&gt;
&lt;h2&gt;Apache 配置&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;修改 Http.conf 文件&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;开启 httpd-vhosts.conf&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;Include /private/etc/apache2/extra/httpd-vhosts.conf&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;开启代理配置&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;
LoadModule proxy_module libexec/apache2/mod_proxy.so
LoadModule proxy_connect_module libexec/apache2/mod_proxy_connect.so
LoadModule proxy_ftp_module libexec/apache2/mod_proxy_ftp.so
LoadModule proxy_http_module libexec/apache2/mod_proxy_http.so

LoadModule proxy_ajp_module libexec/apache2/mod_proxy_ajp.so
LoadModule proxy_balancer_module libexec/apache2/mod_proxy_balancer.so&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;修改 httpd-vhosts.conf 文件&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;替换以下内容&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;
&amp;lt;VirtualHost *:80&amp;gt;
    ServerAdmin test@test.com
    ServerName test.local

    ProxyPreserveHost On
    ProxyRequests Off

    &amp;lt;Proxy /&amp;gt;  
        Order deny,allow  
        Allow from all  
    &amp;lt;/Proxy&amp;gt;  
    ProxyPass / http://192.168.10.10/
    ProxyPassReverse / http://192.168.10.10/
&amp;lt;/VirtualHost&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;重启 Apache&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;service apache reload&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;访问分配的网址就有效果了！&lt;/p&gt;</description>
                <pubDate>Wed, 19 Jun 2019 11:38:58 UTC</pubDate>
                <author>1403749842@qq.com (yiqiao)</author>
                <guid>http://yiqiao.me/articles/19/record-an-apache-port-forwarding-agent</guid>
                <category>Http 服务器</category>
            </item>
                    <item>
                <title>PhpSpreadsheet 导入图片功能</title>
                <link>http://yiqiao.me/articles/18/phpspreadsheet-import-picture-function</link>
                <description>&lt;blockquote&gt;
&lt;p&gt;最近需要做个Excel 图片导入功能，本来是用 Laravel/excel 这个包来做的，虽然方便，但是找了很多资料都没有写，就换了一个包。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;安装&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;composer require phpoffice/phpspreadsheet&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;使用&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;class Import{
private function getEnValue($zhName)
    {
        $column = [
            &#039;名称&#039; =&amp;gt; &#039;name&#039;,
            &#039;图片&#039; =&amp;gt; &#039;image&#039;,
        ];
        return $column[$zhName];
    }
public function import($file, int $sheet = 0, int $columnCnt = 0)
    {
        //设置图片路径
        $folder_name = &quot;uploads/images/customers/&quot; . date(&quot;Ym/d&quot;, time());
        if (!is_dir($folder_name)){
            mkdir($folder_name, 0775);
        }
        try {
            $objRead = IOFactory::createReader(&#039;Xlsx&#039;);
            $obj = $objRead-&amp;gt;load($file);
            $currSheet = $obj-&amp;gt;getSheet($sheet);
            if (0 == $columnCnt) {
                /* 取得最大的列号 */
                $columnH = $currSheet-&amp;gt;getHighestColumn();
                /* 兼容原逻辑，循环时使用的是小于等于 */
                $columnCnt = Coordinate::columnIndexFromString($columnH);
            }
            /* 获取总行数 */
            $rowCnt = $currSheet-&amp;gt;getHighestRow();
            $titlefiled   = [];//excel 字段
            for($i = 1; $i &amp;lt;= $columnCnt; $i ++) {
                $cellName = Coordinate::stringFromColumnIndex($i) . &#039;1&#039;;
                $cellVal = $currSheet-&amp;gt;getCell($cellName)-&amp;gt;getValue();
                $titlefiled[] = $this-&amp;gt;getEnValue($cellVal);
            }
            $data = [];
            for($i = 2; $i &amp;lt;= $rowCnt; $i++) {
                $row = [];
                for($j = 1; $j &amp;lt;= $columnCnt; $j++) {
                    $cellName = Coordinate::stringFromColumnIndex($j) . $i;
                    $cellVal = $currSheet-&amp;gt;getCell($cellName)-&amp;gt;getValue();
                    $key = $titlefiled[$j-1];
                    $row[$key] = $cellVal;
                }
                $data[] = $row;
            }
            $temp = 0;//用于多张图片
            foreach ($currSheet-&amp;gt;getDrawingCollection() as $drawing) {
                if ($drawing instanceof PHPExcel_Worksheet_MemoryDrawing) {
                    ob_start();
                    call_user_func(
                        $drawing-&amp;gt;getRenderingFunction(),
                        $drawing-&amp;gt;getImageResource()
                    );
                    $imageContents = ob_get_contents();
                    ob_end_clean();
                    switch ($drawing-&amp;gt;getMimeType()) {
                        case \PHPExcel_Worksheet_MemoryDrawing::MIMETYPE_PNG :
                            $extension = &#039;png&#039;;
                            break;
                        case \PHPExcel_Worksheet_MemoryDrawing::MIMETYPE_GIF:
                            $extension = &#039;gif&#039;;
                            break;
                        case \PHPExcel_Worksheet_MemoryDrawing::MIMETYPE_JPEG :
                            $extension = &#039;jpg&#039;;
                            break;
                    }
                } else {
                    $zipReader = fopen($drawing-&amp;gt;getPath(), &#039;r&#039;);
                    $imageContents = &#039;&#039;;
                    while (!feof($zipReader)) {
                        $imageContents .= fread($zipReader, 1024);
                    }
                    fclose($zipReader);
                    $extension = $drawing-&amp;gt;getExtension();
                }
                list($startColumn, $startRow) = Coordinate::coordinateFromString($drawing-&amp;gt;getCoordinates());
                $startColumnindex = Coordinate::columnIndexFromString($startColumn) - 1;
                $myFileName = time() . &#039;_&#039; . str_random(10) . &#039;.&#039; . $extension;
                if ($temp == $startColumnindex) {
                    $file = &quot;{$file},&quot;;
                    $file .= &quot;{$folder_name}/{$myFileName}&quot;;
                    $data[$startRow - 2][$titlefiled[$startColumnindex]] = json_encode(explode(&#039;,&#039;, $file));
                } else {
                    $temp = $startColumnindex;
                    $file = &quot;{$folder_name}/{$myFileName}&quot;;
                    $data[$startRow - 2][$titlefiled[$startColumnindex]] = json_encode($file);
                }
                file_put_contents(&quot;{$folder_name}/{$myFileName}&quot;, $imageContents);
            }
            return $data;
        }catch (\Exception $e) {
            throw $e;
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;控制器调用&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;use Import;

class ImportController extends Controller
{
    public funciton import(Request $request, Import $import) {
        $data = $import-&amp;gt;import($request-&amp;gt;file(&#039;file&#039;));
        dd($data);
    }
}&lt;/code&gt;&lt;/pre&gt;</description>
                <pubDate>Mon, 17 Jun 2019 15:31:34 UTC</pubDate>
                <author>1403749842@qq.com (yiqiao)</author>
                <guid>http://yiqiao.me/articles/18/phpspreadsheet-import-picture-function</guid>
                <category>Laravel</category>
            </item>
                    <item>
                <title>Laravel 数组验证</title>
                <link>http://yiqiao.me/articles/17/laravel-array-verification</link>
                <description>&lt;blockquote&gt;
&lt;p&gt;最近我需要一个功能图片上传功能，但是最多只能 10 张，这就需要做判断，但是查了下资料发现都是验证每个字符长度的，而没有验证数组个数的，所以就记录一下&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;return [
    &#039;photo&#039; =&amp;gt; [&quot;array&quot;, &quot;min:1&quot;, &quot;max:10&quot;],//验证 photo 是数组，并且至少 1 张，最多 10 张
    &#039;photo.*&#039;=&amp;gt; [&quot;mimes:jpeg,jpg,png,gif&quot;],//格式必须为 jpeg,jpg,png,gif
];&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;常用案例&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;return [
    &quot;tags&quot; =&amp;gt; [&quot;required&quot;],
    &quot;tags.*&quot;=&amp;gt; [&#039;distinct&#039;, &quot;min:3&quot;, &quot;string&quot;]//验证tags 每个字符都是字符串，不能重复且最少字符串长度为 3
];&lt;/code&gt;&lt;/pre&gt;</description>
                <pubDate>Tue, 21 May 2019 13:48:07 UTC</pubDate>
                <author>1403749842@qq.com (yiqiao)</author>
                <guid>http://yiqiao.me/articles/17/laravel-array-verification</guid>
                <category>Laravel</category>
            </item>
                    <item>
                <title>Blog 床图更换</title>
                <link>http://yiqiao.me/articles/16/blog-bed-diagram-replacement</link>
                <description>&lt;blockquote&gt;
&lt;p&gt;由于新浪前些天限制了外站不能访问图片导致 403 问题，导致本 blog 的所有图片都无法显示，迫于无奈只能更换图床&lt;br /&gt;
再次说明白嫖总会付出代价的。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;经过多次对比我选择了聚合图床，并且添加了友链，有兴趣的可以去看看。也是免费的。虽然不知道啥时候崩，还是先换换看了。&lt;/p&gt;</description>
                <pubDate>Mon, 20 May 2019 11:27:23 UTC</pubDate>
                <author>1403749842@qq.com (yiqiao)</author>
                <guid>http://yiqiao.me/articles/16/blog-bed-diagram-replacement</guid>
                <category>技术之外</category>
            </item>
                    <item>
                <title>Laravel 5.5 Passport OAth 认证</title>
                <link>http://yiqiao.me/articles/15/laravel-55-passport-oath-certification</link>
                <description>&lt;blockquote&gt;
&lt;p&gt;今天做了个项目需要用到前后端分离，所以我写的后端代码都是以接口的形式给前端。研究了下发现在用户登录的时候 session 不起作用，于是使用 Laravel Passport 来解决这个问题。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;本代码环境是 Laravel 5.5 LTS&lt;/h2&gt;
&lt;h2&gt;创建项目&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;composer create-project laravel/laravel passport &quot;5.5.*&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;引入包&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;composer require laravel/passport=~4.0&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Ps.如果报错的话请执行以下代码&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;composer require paragonie/random_compat=~2.0
composer require laravel/passport=~4.0&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Laravel 5.4 以下需要配置 Service Provider&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;config/app.php&lt;/strong&gt; &lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&#039;providers&#039; =&amp;gt; [
    ....
    Laravel\Passport\PassportServiceProvider::class,
]&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;执行迁移文件&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;php artisan migrate&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;接下来，需要使用以下命令。生成秘密访问令牌所需的加密密钥。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;php artisan passport:install&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Passport配置&lt;/h2&gt;
&lt;h3&gt;Model 配置&lt;/h3&gt;
&lt;p&gt;在 app 目录下 &lt;strong&gt;User.php&lt;/strong&gt; 新增 &lt;strong&gt;Laravel\Passport\HasApiTokens&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

namespace App;

use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Laravel\Passport\HasApiTokens;

class User extends Authenticatable
{
    use HasApiTokens, Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        &#039;name&#039;, &#039;email&#039;, &#039;password&#039;,
    ];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        &#039;password&#039;, &#039;remember_token&#039;,
    ];
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;AuthServiceProvider 配置&lt;/h3&gt;
&lt;p&gt;新增 &lt;strong&gt;Passport::routes&lt;/strong&gt; 方法&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

namespace App\Providers;

use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Laravel\Passport\Passport;

class AuthServiceProvider extends ServiceProvider
{
    /**
     * The policy mappings for the application.
     *
     * @var array
     */
    protected $policies = [
        &#039;App\Model&#039; =&amp;gt; &#039;App\Policies\ModelPolicy&#039;,
    ];

    /**
     * Register any authentication / authorization services.
     *
     * @return void
     */
    public function boot()
    {
        $this-&amp;gt;registerPolicies();

        Passport::routes();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;配置文件&lt;/h3&gt;
&lt;p&gt;来到 &lt;strong&gt;config/auth.php&lt;/strong&gt; 修改如下：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;return [
    ....

    &#039;guards&#039; =&amp;gt; [
        &#039;web&#039; =&amp;gt; [
            &#039;driver&#039; =&amp;gt; &#039;session&#039;,
            &#039;provider&#039; =&amp;gt; &#039;users&#039;,
        ],

        &#039;api&#039; =&amp;gt; [
            &#039;driver&#039; =&amp;gt; &#039;passport&#039;,
            &#039;provider&#039; =&amp;gt; &#039;users&#039;,
        ],
    ],

    ....
]&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;创建路由&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;Route::post(&#039;login&#039;, &#039;PassportController@login&#039;);
Route::post(&#039;register&#039;, &#039;PassportController@register&#039;);

Route::middleware(&#039;auth:api&#039;)-&amp;gt;group(function () {
    Route::get(&#039;user&#039;, &#039;PassportController@show&#039;);
});&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;创建控制器&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;php artisan make:controller PassportController&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;复制以下代码：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;?php

namespace App\Http\Controllers;

use App\User;
use Illuminate\Http\Request;

class PassportController extends Controller
{
    /**
     * 用户注册
     *
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function register(Request $request)
    {
        $this-&amp;gt;validate($request, [
            &#039;name&#039; =&amp;gt; &#039;required|min:3&#039;,
            &#039;email&#039; =&amp;gt; &#039;required|email|unique:users&#039;,
            &#039;password&#039; =&amp;gt; &#039;required|min:6&#039;,
        ]);

        $user = User::create([
            &#039;name&#039; =&amp;gt; $request-&amp;gt;name,
            &#039;email&#039; =&amp;gt; $request-&amp;gt;email,
            &#039;password&#039; =&amp;gt; bcrypt($request-&amp;gt;password)
        ]);

        $token = $user-&amp;gt;createToken(&#039;TutsForWeb&#039;)-&amp;gt;accessToken;

        return response()-&amp;gt;json([&#039;token&#039; =&amp;gt; $token], 200);
    }

    /**
     * 用户登录
     *
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function login(Request $request)
    {
        $credentials = [
            &#039;email&#039; =&amp;gt; $request-&amp;gt;email,
            &#039;password&#039; =&amp;gt; $request-&amp;gt;password
        ];

        if (auth()-&amp;gt;attempt($credentials)) {
            $token = auth()-&amp;gt;user()-&amp;gt;createToken(&#039;TutsForWeb&#039;)-&amp;gt;accessToken;
            return response()-&amp;gt;json([&#039;token&#039; =&amp;gt; $token], 200);
        } else {
            return response()-&amp;gt;json([&#039;error&#039; =&amp;gt; &#039;UnAuthorised&#039;], 401);
        }
    }

    /**
     * 用户登录
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function show()
    {
        return response()-&amp;gt;json([&#039;user&#039; =&amp;gt; auth()-&amp;gt;user()], 200);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;测试&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;php artisan serve&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;注册 Api,会返回一个 token 字符串&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;localhost:8080/api/register
name: yiqiao
email: 1@qq.com
password: 123456&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;登录 Api，会返回一个 token 字符串，主要就是拿这个返回的 token 来验证&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;localhost:8080/api/login

POST 请求
email : 1@qq.com
password : 123456&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;查看用户信息 Api 前端需要在请求头加些参数&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&#039;headers&#039; =&amp;gt; [
    &#039;Accept&#039; =&amp;gt; &#039;application/json&#039;,
    &#039;Authorization&#039; =&amp;gt; &#039;Bearer &#039;. $accessToken, （在Bearer 后面是有个空格的）
]&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;localhost:8080/api/user

{
    &quot;user&quot;: {
        &quot;id&quot;: 1,
        &quot;name&quot;: &quot;yiqiao&quot;,
        &quot;created_at&quot;: &quot;2019-05-15 07:29:22&quot;,
        &quot;updated_at&quot;: &quot;2019-05-15 07:29:22&quot;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;详细信息&lt;/h3&gt;
&lt;p&gt;「&lt;a href=&quot;https://learnku.com/docs/laravel/5.5/passport/1309#password-grant-tokens&quot;&gt;Passport OAuth 认证&lt;/a&gt;」&lt;/p&gt;</description>
                <pubDate>Wed, 15 May 2019 16:40:43 UTC</pubDate>
                <author>1403749842@qq.com (yiqiao)</author>
                <guid>http://yiqiao.me/articles/15/laravel-55-passport-oath-certification</guid>
                <category>Laravel</category>
            </item>
                    <item>
                <title>前端配合 layui 原生压缩图片</title>
                <link>http://yiqiao.me/articles/14/front-end-with-layui-original-compressed-picture</link>
                <description>&lt;blockquote&gt;
&lt;p&gt;最近在写图片压缩功能，便在网上找了资料，发现并没有整合 layui，便研究了下&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;需要了解以下知识：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;充分了解三个状态：&lt;code&gt;choose&lt;/code&gt;，&lt;code&gt;before&lt;/code&gt;，&lt;code&gt;done&lt;/code&gt;。&lt;br /&gt;&lt;br /&gt;&lt;code&gt;choose&lt;/code&gt;：表示文件选择后的回调，注意此时并没有加入上传队列；&lt;br /&gt;&lt;br /&gt;&lt;code&gt;before&lt;/code&gt;：表示文件上传前的回调，注意此时已经加入上传队列；&lt;br /&gt;&lt;br /&gt;&lt;code&gt;done&lt;/code&gt;：表示文件上传成功的回调；&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;重点：要使用 &lt;code&gt;choose&lt;/code&gt;，必须设置为 &lt;code&gt;auto&lt;/code&gt;为 &lt;code&gt;false&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;前端压缩代码 JS：&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;//压缩图片
compressImage = (file, success, error) =&amp;gt; {
    // 图片小于1M不压缩
    if (file.size &amp;lt; Math.pow(1024, 2)) {
        return success(file);
    }

    const name = file.name; //文件名
    const reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onload = (e) =&amp;gt; {
        const src = e.target.result;

        const img = new Image();
        img.src = src;
        img.onload = (e) =&amp;gt; {
            const w = img.width;
            const h = img.height;
            const quality = 0.8;  // 默认图片质量为0.92
            //生成canvas
            const canvas = document.createElement(&#039;canvas&#039;);
            const ctx = canvas.getContext(&#039;2d&#039;);
            // 创建属性节点
            const anw = document.createAttribute(&quot;width&quot;);
            anw.nodeValue = w;
            const anh = document.createAttribute(&quot;height&quot;);
            anh.nodeValue = h;
            canvas.setAttributeNode(anw);
            canvas.setAttributeNode(anh);

            //铺底色 PNG转JPEG时透明区域会变黑色
            ctx.fillStyle = &quot;#fff&quot;;
            ctx.fillRect(0, 0, w, h);

            ctx.drawImage(img, 0, 0, w, h);
            // quality值越小，所绘制出的图像越模糊
            const base64 = canvas.toDataURL(&#039;image/jpeg&#039;, quality); //图片格式jpeg或webp可以选0-1质量区间

            // 返回base64转blob的值
            console.log(`原图${(src.length/1024).toFixed(2)}kb`, `新图${(base64.length/1024).toFixed(2)}kb`);
            //去掉url的头，并转换为byte
            const bytes = window.atob(base64.split(&#039;,&#039;)[1]);
            //处理异常,将ascii码小于0的转换为大于0
            const ab = new ArrayBuffer(bytes.length);
            const ia = new Uint8Array(ab);
            for (let i = 0; i &amp;lt; bytes.length; i++) {
                ia[i] = bytes.charCodeAt(i);
            }
            file = new Blob( [ab] , {type : &#039;image/jpeg&#039;});
            file.name = name;
            file.compressImage = true;

            success(file);
        },
        img.onerror = (e) =&amp;gt; {
            error(e);
        }
    },
    reader.onerror = (e) =&amp;gt; {
        error(e);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Layui 图片上传：&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;upload.render({
    elem: &#039;#upload_img_list_button&#039; //绑定元素
    ,url: &#039;/upload-image&#039; //上传接口
    ,accept:&quot;images&quot;
    ,acceptMime: &quot;image/*&quot;
    ,multiple: true
    ,field: &#039;my_image&#039;
    ,auto: false
    // ,size: 2048  // 限制图片2M
    ,choose: function(obj) {
        obj.preview(function(index, file, result){
            compressImage(file, (file)=&amp;gt;{
                obj.upload(index, file);//文件上传
            });
        });
    }
    ,done: function(res){

        //上传完毕回调
        if (res.code == 200) {

        } else {
            layer.msg(res.message);
        }
    }
    ,error: function(){
        layer.msg(&#039;系统错误，请联系管理员&#039;);
    }
    });&lt;/code&gt;&lt;/pre&gt;</description>
                <pubDate>Sat, 09 Mar 2019 10:51:41 UTC</pubDate>
                <author>1403749842@qq.com (yiqiao)</author>
                <guid>http://yiqiao.me/articles/14/front-end-with-layui-original-compressed-picture</guid>
                <category>前端</category>
            </item>
                    <item>
                <title>记一次 vant-list 下拉加载和下拉刷新</title>
                <link>http://yiqiao.me/articles/13/record-a-vant-list-drop-down-load-and-drop-down-refresh</link>
                <description>&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&amp;lt;van-pull-refresh v-model=&quot;isLoading&quot; @refresh=&quot;onRefresh&quot;&amp;gt;
    &amp;lt;van-list v-model=&quot;loading&quot; :finished=&quot;finished&quot; @load=&quot;onLoad&quot;&amp;gt;
        &amp;lt;!-- 内容--&amp;gt;
    &amp;lt;/van-list&amp;gt;
&amp;lt;/van-pull-refresh&amp;gt;

export default{
    data(){
        return {
            list:[],
            page:0,//分页总数
            number:0,//分页数
            loading:false,//控制载入动画
            finished:false,//是否再执行 onLoad方法
            isLoading:false,//控制下拉重新载入
        }
    },
    methods:{
        init(){
            let self = this;
            let data = {
                number : ++self.number
            };
            axios.get(&quot;/get/list&quot;, data, re=&amp;gt;{
                self.list = re.info.list;
                self.page = re.info.page;
                self.isLoading = false;
            });
        },
        onRefresh(){
            let self = this;
            setTimeout(() =&amp;gt; {
                self.page = 0;
                self.init();//加载
            },500);
        },
        onLoad() {
            let self = this;
            let data = {
                page: ++self.number,
            };

            setTimeout(() =&amp;gt; {
                axios.get(&quot;get/list&quot;, {
                    data,
                    success: function(re) {
                        self.page = re.page;
                        self.list = self.list.concat(re.info.list);//追加数据
                        self.loading = false; //加载状态结束

                        // 数据全部加载完成

                        if (self.totalPage &amp;lt;= self.pageNumber) {
                            self.finished = true;
                        }
                    }
                });
            }, 500);
        }
    }
}&lt;/code&gt;&lt;/pre&gt;</description>
                <pubDate>Sat, 09 Mar 2019 10:50:01 UTC</pubDate>
                <author>1403749842@qq.com (yiqiao)</author>
                <guid>http://yiqiao.me/articles/13/record-a-vant-list-drop-down-load-and-drop-down-refresh</guid>
                <category>前端</category>
            </item>
                    <item>
                <title>git 批量修改提交 username、email</title>
                <link>http://yiqiao.me/articles/12/git-batch-modification-submission-username-email</link>
                <description>&lt;h2&gt;克隆仓库&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;git clone --bare https://github.com/user/repo.git
cd repo.git&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;命令行中运行代码&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;OLD_EMAIL：原来的邮箱&lt;br /&gt;&lt;br /&gt;
CORRECT_NAME：更正的名字&lt;br /&gt;CORRECT_EMAIL：更正的邮箱&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;将下面代码复制放到命令行中执行&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;git filter-branch -f --env-filter &#039;
OLD_EMAIL=&quot;原来的邮箱&quot;
CORRECT_NAME=&quot;更正的名字&quot;
CORRECT_EMAIL=&quot;更正的邮箱&quot;
if [ &quot;$GIT_COMMITTER_EMAIL&quot; = &quot;$OLD_EMAIL&quot; ]
then
    export GIT_COMMITTER_NAME=&quot;$CORRECT_NAME&quot;
    export GIT_COMMITTER_EMAIL=&quot;$CORRECT_EMAIL&quot;
fi
if [ &quot;$GIT_AUTHOR_EMAIL&quot; = &quot;$OLD_EMAIL&quot; ]
then
    export GIT_AUTHOR_NAME=&quot;$CORRECT_NAME&quot;
    export GIT_AUTHOR_EMAIL=&quot;$CORRECT_EMAIL&quot;
fi
&#039; --tag-name-filter cat -- --branches --tags&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;执行后等待一会&lt;/p&gt;
&lt;h2&gt;同步到远程库&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;git push --force --tags origin &#039;refs/heads/*&#039;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;remote: GitLab: You are not allowed to force push code to a protected branch on this project.&lt;br /&gt;
若遇到以上错误。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;code&gt;git pull&lt;/code&gt; 确保最新代码&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;git pull  --allow-unrelated-histories
# 或者指定分枝
git pull origin master --allow-unrelated-histories&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;fatal: This operation must be run in a work tree 若提示这行报错。&lt;br /&gt;
请在在工作目录运行。&lt;/p&gt;
&lt;/blockquote&gt;</description>
                <pubDate>Sat, 09 Mar 2019 10:46:52 UTC</pubDate>
                <author>1403749842@qq.com (yiqiao)</author>
                <guid>http://yiqiao.me/articles/12/git-batch-modification-submission-username-email</guid>
                <category>版本控制</category>
            </item>
                    <item>
                <title>使用 brew-php-switcher 管理 Mac php版本</title>
                <link>http://yiqiao.me/articles/11/managing-mac-php-version-with-brew-php-switch</link>
                <description>&lt;blockquote&gt;
&lt;p&gt;由于 Mac 自带的 PHP 版本过低，就在 homestead 上下载了个 7.1 版本，但是没法自动切换，所以安装了个版本控制。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;安装 php&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;brew install php@7.1&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;安装 brew-php-switcher&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;brew install brew-php-switcher
切换版本：
brew-php-switcher 5.6&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;注意：默认情况会切换 apache 配置&lt;/p&gt;
&lt;/blockquote&gt;</description>
                <pubDate>Fri, 14 Dec 2018 00:47:33 UTC</pubDate>
                <author>1403749842@qq.com (yiqiao)</author>
                <guid>http://yiqiao.me/articles/11/managing-mac-php-version-with-brew-php-switch</guid>
                <category>PHP</category>
            </item>
                    <item>
                <title>抵制 CSDN 从我做起！！！！</title>
                <link>http://yiqiao.me/articles/10/resist-csdn-from-me</link>
                <description>&lt;p&gt;最近 &lt;code&gt;CSDN&lt;/code&gt; 挺出现闹心的事，想看内容必须登录，而且是强制性的。挺反感这种行为。于是就想在搜索结果去掉 csdn 显示的内容。&lt;/p&gt;
&lt;h2&gt;第一种：简单粗暴式&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;搜索内容+ -csdn
例如： 为什么 csdn 要登录 -csdn&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;第二种：安装插件去除&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;需要在 google 浏览器运行&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;去 google 应用商店搜索 &lt;code&gt;Tampermonkey&lt;/code&gt; 并且安装。安装后访问 &lt;a href=&quot;https://greasyfork.org/zh-CN/scripts/1682-google-hit-hider-by-domain-search-filter-block-sites&quot;&gt;block 脚本&lt;/a&gt; 也安装了。&lt;br /&gt;
之后 google 或者 baidu 一下。搜索列表注意链接后边有 &lt;code&gt;block&lt;/code&gt; 按钮，点击后有个 &lt;code&gt;block site&lt;/code&gt; 选项，选择后即可 &lt;code&gt;block&lt;/code&gt; 该网站。&lt;/p&gt;</description>
                <pubDate>Thu, 06 Dec 2018 10:56:07 UTC</pubDate>
                <author>1403749842@qq.com (yiqiao)</author>
                <guid>http://yiqiao.me/articles/10/resist-csdn-from-me</guid>
                <category>技术之外</category>
            </item>
                    <item>
                <title>Homebrew 安装指定版本 Node</title>
                <link>http://yiqiao.me/articles/9/homebrew-installs-the-specified-version-of-node</link>
                <description>&lt;h3&gt;前言&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;npm&lt;/code&gt; 环境被我玩坏了，随后重新安装整个 &lt;code&gt;node&lt;/code&gt; 环境，结果发现 &lt;code&gt;brew&lt;/code&gt; 默认是最新版本，但是我的当前环境不适合最新版本（前端从入门到放弃系列）&lt;/p&gt;
&lt;h3&gt;安装&lt;/h3&gt;
&lt;p&gt;首先看 &lt;code&gt;node&lt;/code&gt; 包有几个版本&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;brew search node&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如图所示，图中我已经安装好指定版本了&lt;br /&gt;&lt;img src=&quot;https://pic.superbed.cn/item/5ce21577697df1fd0c0a15ef.jpg&quot; alt=&quot;列表&quot; /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;清理老版本没安装过可忽略&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;code&gt;brew uninstall --ignore-dependencies node&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;安装指定版本&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;brew install node@8&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后 &lt;code&gt;brew link node@8&lt;/code&gt;, 这一步可能会报错, 按照提示执行命令就 ok 了, 比如我最后执行的是 &lt;code&gt;brew link --overwrite --force node@8&lt;/code&gt;。&lt;/p&gt;
&lt;h3&gt;查看版本&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;node -v 输出版本号就安装成功了！&lt;/code&gt;&lt;/pre&gt;</description>
                <pubDate>Wed, 05 Dec 2018 00:25:02 UTC</pubDate>
                <author>1403749842@qq.com (yiqiao)</author>
                <guid>http://yiqiao.me/articles/9/homebrew-installs-the-specified-version-of-node</guid>
                <category>前端</category>
            </item>
                    <item>
                <title>PHPUnit 6.5.13 安装</title>
                <link>http://yiqiao.me/articles/8/phpunit-6513-installation</link>
                <description>&lt;p&gt;由于 &lt;code&gt;brew&lt;/code&gt; 目前下载的 &lt;code&gt;phpunit&lt;/code&gt; 是最新版「7.0+」，我需要旧的 &lt;code&gt;phpunit&lt;/code&gt; 版本「6.0+」。所以在官网找了历史包。&lt;/p&gt;
&lt;h2&gt;命令&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;wget -O phpunit https://phar.phpunit.de/phpunit-6.phar
chmod +x phpunit
sudo mv phpunit /usr/local/bin/phpunit
phpunit --version 输出版本号即安装成功！&lt;/code&gt;&lt;/pre&gt;</description>
                <pubDate>Wed, 05 Dec 2018 00:01:27 UTC</pubDate>
                <author>1403749842@qq.com (yiqiao)</author>
                <guid>http://yiqiao.me/articles/8/phpunit-6513-installation</guid>
                <category>Laravel</category>
            </item>
                    <item>
                <title>「已失效」搬瓦工更换 IP</title>
                <link>http://yiqiao.me/articles/7/move-the-mason-to-replace-ip</link>
                <description>&lt;h2&gt;前言&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;前几天发现我用搬瓦工无法翻墙，一般换端口密码以及重启就好，但是这回就不行了&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;检查 IP 是否被 ban&lt;/h2&gt;
&lt;p&gt;首先登陆我们被封了 IP 的 VPS 的 KiwiVM 面板，这个怎么登陆就不多说了，大家都会吧。登陆之后，打开下面网址：&lt;br /&gt;&lt;a href=&quot;https://kiwivm.64clouds.com/main-exec.php?mode=blacklistcheck&quot;&gt;https://kiwivm.64clouds.com/main-exec.php?mode=blacklistcheck&lt;/a&gt;&lt;br /&gt;
打开之后，会检查你的 IP 地址是否已经被封，我们点击“Test Main IP”进行测试。&lt;br /&gt;
如果没有被封，会显示如下结果，&lt;em&gt;IP NOT BLOCKED&lt;/em&gt;。&lt;br /&gt;
如果被封了，会显示红色的字眼 &lt;em&gt;IP BLICKED&lt;/em&gt;。&lt;br /&gt;
这时候我们只需点击下面的 “Replace Main IP”，进行更换 IP 的操作。&lt;/p&gt;
&lt;p&gt;点击 Replace Main IP 之后，可以看到如下页面，显示 IP Replaced successfully，也就是 IP 替换成功了。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Tip: 这个是免费的，每 5 周可以换一次 IP。如果 5 周内还被ban 了要么等 5 周，要么就付费换 IP 了（付费换 IP 有点贵）。&lt;/p&gt;
&lt;/blockquote&gt;</description>
                <pubDate>Sun, 14 Oct 2018 22:20:03 UTC</pubDate>
                <author>1403749842@qq.com (yiqiao)</author>
                <guid>http://yiqiao.me/articles/7/move-the-mason-to-replace-ip</guid>
                <category>技术之外</category>
            </item>
                    <item>
                <title>acme.sh 来给网站升级 HTTPS</title>
                <link>http://yiqiao.me/articles/6/acmesh-to-upgrade-website-to-https</link>
                <description>&lt;h2&gt;acme.sh 实现 &lt;code&gt;acme&lt;/code&gt; 协议，可以从 letsencrypt 生成免费的证书。&lt;/h2&gt;
&lt;h3&gt;安装步骤&lt;/h3&gt;
&lt;ul&gt;&lt;li&gt;安装 acme.sh&lt;/li&gt;
&lt;li&gt;生成证书&lt;/li&gt;
&lt;li&gt;copy 证书到 nginx/apache 或者其他服务&lt;/li&gt;
&lt;li&gt;更新证书&lt;/li&gt;
&lt;li&gt;更新acme.sh&lt;/li&gt;
&lt;li&gt;出错调试&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;1.安装 acme.sh&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;curl https://get.acme.sh | sh&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;安装过程不会污染已有系统任何功能和文件&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;2.生成证书&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;acme.sh --issue -d domain.com --webroot /home/www/html&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果你用的 &lt;strong&gt;apache&lt;/strong&gt; 服务器, acme.sh 还可以智能的从 &lt;strong&gt;apache&lt;/strong&gt; 的配置中自动完成验证, 你不需要指定网站根目录:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;acme.sh --issue  -d domain.com   --apache&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Nginx&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;acme.sh --issue  -d domain.com   --nginx&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;注意, 无论是 apache 还是 nginx 模式, acme.sh在完成验证之后, 会恢复到之前的状态, 都不会私自更改你本身的配置. 好处是你不用担心配置被搞坏, 也有一个缺点, 你需要自己配置 ssl 的配置, 否则只能成功生成证书, 你的网站还是无法访问https. 但是为了安全, 你还是自己手动改配置吧.&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;3. copy/安装证书&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;acme.sh  --installcert  -d  &amp;lt;domain&amp;gt;.com   \
        --key-file   /etc/nginx/ssl/&amp;lt;domain&amp;gt;.key \
        --fullchain-file /etc/nginx/ssl/fullchain.cer \
        --reloadcmd  &quot;service nginx force-reload&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;一个小提醒, 这里用的是 &lt;code&gt;service nginx force-reload&lt;/code&gt;, 不是 &lt;code&gt;service nginx reload&lt;/code&gt;, 据测试, &lt;code&gt;reload&lt;/code&gt; 并不会重新加载证书, 所以用的 &lt;code&gt;force-reload&lt;/code&gt;)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Nginx 的配置 &lt;code&gt;ssl_certificate&lt;/code&gt; 使用 &lt;code&gt;/etc/nginx/ssl/fullchain.cer&lt;/code&gt; ，而非 &lt;code&gt;/etc/nginx/ssl/&amp;lt;domain&amp;gt;.cer&lt;/code&gt;，否则 SSL Labs 的测试会报 &lt;code&gt;Chain issues Incomplete&lt;/code&gt; 错误&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;如果没有自动生成配置文件的话，自己去加，这里我用自己的例子&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;cd /etc/nginx/site-available
vi domain
server
{
    listen    80;
    server_name    domain.com;
    root    /var/www/html/public;
    index index.php index.html index.htm;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
                try_files $uri /index.php =404;
                fastcgi_split_path_info ^(.+\.php)(/.+)$;
                fastcgi_pass unix:/var/run/php/php7.1-fpm.sock;
                fastcgi_index index.php;
                fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
                include fastcgi_params;
    }

    listen 443 ssl http2;
    ssl_certificate /etc/nginx/ssl/fullchain.cer;
    ssl_certificate_key /etc/nginx/ssl/&amp;lt;domain&amp;gt;.key;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4.更新证书&lt;/h3&gt;
&lt;p&gt;自动更新&lt;/p&gt;
&lt;h3&gt;5.更新 acme.sh&lt;/h3&gt;
&lt;p&gt;手动升级&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;acme.sh --upgrade&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;自动升级&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;acme.sh  --upgrade  --auto-upgrade&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;关闭自动更新&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;acme.sh  --upgrade  --auto-upgrade 0&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;6.出错调试&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;acme.sh  --issue  .....  --debug &lt;/code&gt;&lt;/pre&gt;</description>
                <pubDate>Wed, 29 Aug 2018 11:12:06 UTC</pubDate>
                <author>1403749842@qq.com (yiqiao)</author>
                <guid>http://yiqiao.me/articles/6/acmesh-to-upgrade-website-to-https</guid>
                <category>Linux</category>
            </item>
                    <item>
                <title>Laravel 使用 group by 报错</title>
                <link>http://yiqiao.me/articles/5/laravel-uses-group-by-to-report-errors</link>
                <description>&lt;blockquote&gt;
&lt;p&gt;在 mysql 5.7 中，用group by 查询时抛出如下异常：&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;Expression #1 of SELECT list is not in GROUP BY 
clause and contains nonaggregated column &#039;xxx&#039; 
which is not functionally dependent on columns in 
GROUP BY clause; this is incompatible with 
sql_mode=only_full_group_by&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;查询资料原因如下：&lt;/h3&gt;
&lt;p&gt;MySQL 5.7.5 实现了对功能依赖的检测。如果启用了only_full_group_by SQL模式(在默认情况下是这样)，那么 MySQL 就会拒绝选择列表、条件或顺序列表引用的查询，这些查询将引用组中未命名的非聚合列，而不是在功能上依赖于它们。(在5.7.5之前，MySQL没有检测到功能依赖项，only_full_group_by在默认情况下是不启用的。关于前5.7.5行为的描述，请参阅 &lt;a href=&quot;https://dev.mysql.com/doc/refman/5.7/en/group-by-handling.html&quot;&gt;MySQL 5.6参考手册&lt;/a&gt;。)&lt;/p&gt;
&lt;h2&gt;群友方法&lt;/h2&gt;
&lt;p&gt;修改 &lt;code&gt;app/database.php&lt;/code&gt; 文件中 &lt;code&gt;mysql&lt;/code&gt; 参数，改动如下：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;&#039;mysql&#039; =&amp;gt; [
            &#039;driver&#039; =&amp;gt; &#039;mysql&#039;,
            &#039;host&#039; =&amp;gt; env(&#039;DB_HOST&#039;, &#039;127.0.0.1&#039;),
            &#039;port&#039; =&amp;gt; env(&#039;DB_PORT&#039;, &#039;3306&#039;),
            &#039;database&#039; =&amp;gt; env(&#039;DB_DATABASE&#039;, &#039;forge&#039;),
            &#039;username&#039; =&amp;gt; env(&#039;DB_USERNAME&#039;, &#039;forge&#039;),
            &#039;password&#039; =&amp;gt; env(&#039;DB_PASSWORD&#039;, &#039;&#039;),
            &#039;unix_socket&#039; =&amp;gt; env(&#039;DB_SOCKET&#039;, &#039;&#039;),
            &#039;charset&#039; =&amp;gt; &#039;utf8mb4&#039;,
            &#039;collation&#039; =&amp;gt; &#039;utf8mb4_unicode_ci&#039;,
            &#039;prefix&#039; =&amp;gt; &#039;&#039;,
            &#039;strict&#039; =&amp;gt; false,
            &#039;engine&#039; =&amp;gt; null,
        ],&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;我的方法&lt;/h2&gt;
&lt;p&gt;在 mysql 命令行执行如下命令：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;mysql&amp;gt; select @@sql_mode;
结果为：
ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,
NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,
NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;解决方案：&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;A.执行命令&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;mysql&amp;gt; set global sql_mode=&#039;STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION&#039;;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;B.修改 mysql 配置文件 my.cnf&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;sudo vim /etc/mysql/conf.d/mysql.cnf&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;设置&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;[mysqld]
sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,
ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,
NO_ENGINE_SUBSTITUTION&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;保存并重启&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;sudo service mysql restart&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;设置后还是没法搜索的话，可以使用如下 mysql 语句&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;select 列名 from 表名 group by 列名
使用聚合函数，例如 sum()
select 列名,sum(列名) from 表名 group by 列名&lt;/code&gt;&lt;/pre&gt;</description>
                <pubDate>Wed, 29 Aug 2018 11:10:24 UTC</pubDate>
                <author>1403749842@qq.com (yiqiao)</author>
                <guid>http://yiqiao.me/articles/5/laravel-uses-group-by-to-report-errors</guid>
                <category>Laravel</category>
            </item>
                    <item>
                <title>Ubuntu Nginx 多站点配置</title>
                <link>http://yiqiao.me/articles/4/ubuntu-nginx-multi-site-configuration</link>
                <description>&lt;h2&gt;1. 安装 Nginx&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;sudo apt-get install nginx&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;2.创建新的文件路径&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;sudo mkdir -p /var/www/one.com
sudo mkdir -p /var/www/two.com&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以上的命令就会创建两个对应的目录：主要将 one.com 和 two.com 换成你自己的域名。然后再将这两个文件夹给定权限和所有权：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;sudo chown -R www-data:www-data /var/www/one.com/html
sudo chown -R www-data:www-data /var/www/two.com/html&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上面的 www-data:www-data 就是 Nginx 默认的用户组合用户名&lt;/p&gt;
&lt;h2&gt;3.创建不同的入口文件&lt;/h2&gt;
&lt;p&gt;站点一:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;sudo vi /var/www/one.com/index.html&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;内容如下：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;This is One&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;站点二：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;sudo vi /var/www/two.com/index.html&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;内容如下：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;This is Two&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4.创建不同的配置文件&lt;/h3&gt;
&lt;p&gt;在安装完 Nginx 之后，其实 Nginx 的默认配置文件实在 &lt;code&gt;/etc/nginx/sites-available/default&lt;/code&gt; 的，但是我们要配置多站点的话，可以这样：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;sudo vi etc/nginx/sites-available/one.com&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;内容如下：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;server {
        listen 80;
        listen [::]:80;

        root /var/www/one.com/html;
        index index.html index.htm index.nginx-debian.html;

        server_name one.com www.one.com;

        location / {
                try_files $uri $uri/ =404;
        }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;站点二配置和上面一样，只不过改下里面的 &lt;code&gt;one.com&lt;/code&gt; 换成 &lt;code&gt;two.com&lt;/code&gt; 就好，配置后删除原来的 &lt;code&gt;default&lt;/code&gt; 配置文件&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;sudo rm etc/nginx/sites-available/default&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;5.建立软链接&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;sudo ln -s /etc/nginx/sites-available/one.com /etc/nginx/sites-enabled/

sudo ln -s /etc/nginx/sites-available/two.com /etc/nginx/sites-enabled/&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;执行上面的命令之后，我们再使用 nginx -t 检测 Nginx 的配置文件是否有错：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;sudo nginx -t&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;没有报错后执行重启命令即可：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;sudo service nginx restart&lt;/code&gt;&lt;/pre&gt;</description>
                <pubDate>Wed, 29 Aug 2018 11:07:03 UTC</pubDate>
                <author>1403749842@qq.com (yiqiao)</author>
                <guid>http://yiqiao.me/articles/4/ubuntu-nginx-multi-site-configuration</guid>
                <category>Linux</category>
            </item>
                    <item>
                <title>「已失效」如何搭建自己的梯子</title>
                <link>http://yiqiao.me/articles/3/how-to-build-your-own-ladder</link>
                <description>&lt;h2&gt;声明&lt;/h2&gt;
&lt;p&gt;&lt;del&gt;已没有 20 刀 / 年，本帖只有搭建教程可以看了，不推荐购买了&lt;/del&gt;&lt;/p&gt;
&lt;h2&gt;说明&lt;/h2&gt;
&lt;p&gt;作为一名程序员，有时候搜索问题的时候还是 &lt;strong&gt;Google&lt;/strong&gt; 好用，但是在国内却是 404 网页。通过 hosts 修改文件来访问也很慢。所以我推荐一个 VPS 站点。主要是它支持 &lt;strong&gt;支付宝&lt;/strong&gt; 支付，以及 &lt;strong&gt;一键安装&lt;/strong&gt; 功能。&lt;/p&gt;
&lt;h3&gt;VPS 购买地址： &lt;a href=&quot;https://bwh1.net/aff.php?aff=14780&quot;&gt;点我跳转&lt;/a&gt;&lt;/h3&gt;
&lt;h2&gt;选择 VPS 服务&lt;/h2&gt;
&lt;p&gt;首先先去 &lt;a href=&quot;https://bwh1.net/aff.php?aff=14780&quot;&gt;VPS站点&lt;/a&gt; 购买主机（按年交要 49.99 每刀）。&lt;br /&gt;
选好配置和时间后点击最下面的 Add a cart。&lt;/p&gt;
&lt;h3&gt;购买 VPS&lt;/h3&gt;
&lt;p&gt;显示出订单信息后点击 &lt;strong&gt;Check out&lt;/strong&gt;，接着显示订单列表。&lt;br /&gt;&lt;img src=&quot;https://pic.superbed.cn/item/5ce212a3697df1fd0c09f742.jpg&quot; alt=&quot;注册页面&quot; /&gt;&lt;br /&gt;
填写成功后去支付。支付成功后。登录进去，找到自己刚刚购买的 VPS 服务。&lt;br /&gt;&lt;img src=&quot;https://pic1.superbed.cn/item/5ce212ba697df1fd0c09f85f.jpg&quot; alt=&quot;配置&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;一键安装 SS&lt;/h2&gt;
&lt;p&gt;进入控制面板点击最下面 &lt;code&gt;Shadowsocks Server&lt;/code&gt;，然后点击安装，等待片刻后出现下图相关配置。&lt;br /&gt;&lt;img src=&quot;https://pic.superbed.cn/item/5ce212ae697df1fd0c09f7cc.jpg&quot; alt=&quot;SS安装&quot; /&gt;&lt;br /&gt;
最后安装所属的软件进行配置就好了。&lt;br /&gt;
最后使用 SS 客户端登录即可&lt;br /&gt;
下载地址：&lt;a href=&quot;https://github.com/shadowsocks/shadowsocks-windows/releases&quot;&gt;Windows&lt;/a&gt; | &lt;a href=&quot;https://github.com/shadowsocks/ShadowsocksX-NG/releases/&quot;&gt;MacOS&lt;/a&gt;&lt;/p&gt;</description>
                <pubDate>Wed, 29 Aug 2018 10:20:36 UTC</pubDate>
                <author>1403749842@qq.com (yiqiao)</author>
                <guid>http://yiqiao.me/articles/3/how-to-build-your-own-ladder</guid>
                <category>技术之外</category>
            </item>
                    <item>
                <title>服务器MySQL 远程连接设置</title>
                <link>http://yiqiao.me/articles/2/server-mysql-remote-connection-settings</link>
                <description>&lt;h2&gt;说明&lt;/h2&gt;
&lt;p&gt;使用 MySQL GUI 连接VPS的 MySQL 服务器连接失败，经查是以下原因引起的：&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;数据库默认只允许本地连接，拒绝远程连接。&lt;/li&gt;
&lt;li&gt;所使用 root 账号无远程连接权限，需要设置权限，或新建账号用于远程连接。&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;解决方案&lt;/h2&gt;
&lt;h3&gt;建远程连接账号，给 root 开通远程连接权限&lt;/h3&gt;
&lt;ul&gt;&lt;li&gt;MySQL&lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;mysql -u root -p&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;&lt;li&gt;创建新用户&lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;CREATE USER &#039;username&#039;@&#039;%&#039; IDENTIFIED BY &#039;password&#039;;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;注意：&lt;code&gt;@&lt;/code&gt; 左边是用户名，右边是域名、IP 和 &lt;code&gt;%&lt;/code&gt;，表示可以访问 mysql 的域名和 IP，% 表示外部任何地址都能访问。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;给新用户和 root 赋值所有权限&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;-- 给新用户权限
GRANT ALL PRIVILEGES ON *.* TO &#039;username&#039;@&#039;localhost&#039; IDENTIFIED BY &#039;password&#039;;
GRANT ALL PRIVILEGES ON *.* TO &#039;username&#039;@&#039;%&#039; IDENTIFIED BY &#039;password&#039;;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Tip: 格的安全考虑的话，生产环境请将 % 换成特定的 IP。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;&lt;li&gt;立即刷新权限&lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;FLUSH PRIVILEGES;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;更改 MySQL 配置，允许远程连接&lt;/h3&gt;
&lt;p&gt;MySQL 无法连接的可能原因是服务器防火墙未放开 3306 端口，或 MySQL 服务器禁止远程连接了。&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;查看 3306 端口是否开放&lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;netstat -an | grep 3306&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;tcp6       0      0 127.0.0.1:3306                 0.0.0.0:*                    LISTEN&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如上表示 3306 端口并未打开。进入 MySQL 配置目录：&lt;code&gt;etc/mysql/mysql.conf.d/&lt;/code&gt;编辑配置文件：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;cd /etc/mysql/mysql.conf.d
sudo vim mysqld.cnf&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;MySQL 默认只允许本地服务器访问，注释以下配置：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;# bind-address = 127.0.0.1&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;保存并退出，然后重启 MySQL 服务：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;sudo service mysql restart&lt;/code&gt;&lt;/pre&gt;</description>
                <pubDate>Wed, 29 Aug 2018 10:10:51 UTC</pubDate>
                <author>1403749842@qq.com (yiqiao)</author>
                <guid>http://yiqiao.me/articles/2/server-mysql-remote-connection-settings</guid>
                <category>Linux</category>
            </item>
                    <item>
                <title>Ubuntu 14/16 下的 Laravel LNMP 线上环境自动部署脚本</title>
                <link>http://yiqiao.me/articles/1/automatic-deployment-scripts-for-laravel-lnmp-online-environment-under-ubuntu-16</link>
                <description>&lt;h2&gt;说明&lt;/h2&gt;
&lt;p&gt;此脚本用于在一台全新的 Ubuntu 16.04 LTS 上部署适合 Laravel 使用的 LNMP 生产环境。&lt;/p&gt;
&lt;h2&gt;安装步骤&lt;/h2&gt;
&lt;p&gt;1). 下载 &lt;code&gt;deploy-16.sh&lt;/code&gt; 脚本&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;wget https://gist.githubusercontent.com/PerJoy/422fff78b6dc7c67c934ae2686f1b1df/raw/f2436e5f5412c866f5f78b715b75b20320e3f5e7/deploy-16.sh
chmod +x deploy-16.sh&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;2).设置 MYSQL 密码&lt;br /&gt;&lt;code&gt;vi deploy.sh&lt;/code&gt; 根据情况修改以下：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;# Configure
MYSQL_ROOT_PASSWORD=&quot;这里填写复杂的密码&quot;
MYSQL_NORMAL_USER=&quot;estuser&quot;
MYSQL_NORMAL_USER_PASSWORD=&quot;这里填写复杂的密码&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;3). 开始安装&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;有需要的话可以使用网易镜像加速：&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;wget http://mirrors.163.com/.help/sources.list.trusty -O /etc/apt/sources.list&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;开始安装：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;./deploy.sh&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;注：请使用 root 运行。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;安装后会有类似输出：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;--
--
It&#039;s Done.
Mysql Root Password: xxx你的密码xxx
Mysql Normal User: estuser
Mysql Normal User Password: xxx你的密码xxx
--
--&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;安装完以后的配置和注意事项&lt;/h2&gt;
&lt;h3&gt;1. 修改站点目录权限&lt;/h3&gt;
&lt;p&gt;通过此脚本配置的 Nginx 将使用 www 用户权限，因此需要在你的站点根目录下运行以下命令更新权限。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;cd /data/www/{你的网站目录}
chown www:www -R ./&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. 添加站点的 Nginx 配置&lt;/h3&gt;
&lt;p&gt;下面是站点的 Nginx 配置模板，写入按照域名命名的文件中，并放入到 /etc/nginx/sites-enabled 目录下。如：&lt;code&gt;/etc/nginx/sites-enabled/blog&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;server {
    listen 80;
    server_name {你的域名};
    root &quot;{站点根目录}&quot;;

    index index.html index.htm index.php;

    charset utf-8;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location = /favicon.ico { access_log off; log_not_found off; }
    location = /robots.txt  { access_log off; log_not_found off; }

    access_log /data/log/nginx/{你的网站标识}-access.log;
    error_log  /data/log/nginx/{你的网站标识}-error.log error;

    sendfile off;

    client_max_body_size 100m;

    include fastcgi.conf;

    location ~ /\.ht {
        deny all;
    }

    location ~ \.php$ {
        fastcgi_pass   127.0.0.1:9000;
        #fastcgi_pass /run/php/php7.0-fpm.sock;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        include        fastcgi_params;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;配置完以后重启 Nginx 即可。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;service nginx restart&lt;/code&gt;&lt;/pre&gt;</description>
                <pubDate>Tue, 28 Aug 2018 18:06:33 UTC</pubDate>
                <author>1403749842@qq.com (yiqiao)</author>
                <guid>http://yiqiao.me/articles/1/automatic-deployment-scripts-for-laravel-lnmp-online-environment-under-ubuntu-16</guid>
                <category>Laravel</category>
            </item>
            </channel>
</rss>
