在 laravel 开发中遇到了这样的问题,业务代码中调用 env() 获取环境变量,结果无法获取。

原因如官方文档所述:

为了给你的应用程序提升速度,你应该使用 Artisan 命令 config:cache 将所有的配置文件缓存到单个文件中。这会把你的应用程序中所有的配置选项合并成一个单一的文件,然后框架会快速加载这个文件。
通常来说,你应该把运行 php artisan config:cache 命令作为生产环境部署常规的一部分。这个命令不应在本地开发环境下运行,因为配置选项在应用程序开发过程中是经常需要被更改的。
如果在部署过程中执行 config:cache 命令,那你应该确保只从配置文件内部调用 env 函数。

意思是说,在你的业务代码中,不能使用 env() 方法。

原因何在?

在 Laravel 中,如果执行 php aritisan config:cache 命令,Laravel 将会把 app/config 目录下的所有配置文件“编译”整合成一个缓存配置文件到 bootstrap/cache/config.php,每个配置文件都可以通过 env 函数读取环境变量,这里是可以读取的。但是一旦有了这个缓存配置文件,在其他地方使用 env 函数是读取不到环境变量的,所以返回 null.

让我们看看这段代码,Illuminate/Foundation/Bootstrap/DetectEnvironment.php line 18:

public function bootstrap(Application $app)
{
    if (! $app->configurationIsCached()) {
        $this->checkForSpecificEnvironmentFile($app);

        try {
            (new Dotenv($app->environmentPath(), $app->environmentFile()))->load();
        } catch (InvalidPathException $e) {
            //
        }
    }
}

这个方法在框架启动后就会运行,如果存在缓存配置文件,就不会去设置环境变量了。

因此,在配置文件即 app/config 目录下的其他地方,读取配置不要使用 env 函数去读环境变量,这样你一旦执行 php artisan config:cache 之后,env 函数就不起作用了。所有要用到的环境变量,在 app/config 目录的配置文件中通过 env 读取,其他地方要用到环境变量的都统一读配置文件而不是使用 env 函数读取。

环境:

  • ubuntu 16.04
  • php7.2

一、安装 php7.2-dev

apt-get install php7.2-dev -y

二、下载并编译 xdebug

  • 下载 xdebug 最新的源码包
wget https://xdebug.org/files/xdebug-2.6.0.tgz
  • 解压缩
tar -zxvf xdebug-2.6.0.tgz
  • 编译安装
cd xdebug-2.6.0
phpize
/configure --enable-xdebug
make
make install

三、配置

  • 在 cd /etc/php/7.2/mods-available 目录中,增加 xdebug.ini
extension=xdebug.so
xdebug.remote_enable = 1
xdebug.remote_port = 9001
xdebug.idekey = PHPSTORM
xdebug.show_error_trace = 1
xdebug.remote_autostart = 0
xdebug.file_link_format = phpstorm://open?%f:%l
  • 增加软连接
cd /etc/php/7.2/fpm/conf.d/
sudo ln -s /etc/php/7.2/mods-available/xdebug.ini 20-xdebug.ini
cd /etc/php/7.2/cli/conf.d/
sudo ln -s /etc/php/7.2/mods-available/xdebug.ini 20-xdebug.ini

四、测试

  1. cli 环境下,查看 php -m
  2. 测试 phpinfo,查看 xdebug 的信息 (略)
  3. phpstorm 测试 xdebug

在 openresty 中,要对部分特殊的 url 进行 rewrite,由于 url 比较多,还经常变动,rewrite 时还需要做判断,因此考虑使用 lua 进行处理。

在这个过程中,希望把特殊的 url 作为配置文件写入 table,然后进行判断,那么 lua 如何读取一个配置文件呢?

其实很简单,在 lua 脚本中使用 dofile 即可:

dofile "myconfig.lua"
dofile "/usr/share/myapp/config.lua"

这样的方式比较简单,但是如果遇到错误,会导致整个程序停止运行,如果你希望在遇到读取文件发生错误的时候抛出异常,可以使用以下的方式:

local ok,e = pcall(dofile,"myconfig.lua")
if not ok then
  -- handle error; e has the error message
end

MySQL slow query log consists of SQL statements that took more than long_query_time seconds to complete execution & required atleast min_examined_row_limit to be examined. By default, administrative queries & those that don’t use indexes for lookups are not logged.

Two common techniques used by Logrotate are:

copytruncate: Instead of moving the old log file & optionally creating a new one, logrotate truncates the original log file in place after creating a copy.
nocopytruncate: Do not truncate the original log file in place after creating a copy.
Truncating log files can block MySQL because the OS serializes access to the inode during the truncate operation. Therefore, it is recommended to temporarily stop slow query logging, flush slow logs, rename the old log file & finally re-enable slow query logging.

Flushing logs might take a considerable amount of time, so, to avoid filling slow log buffer, it’s advisable to temporarily disable MySQL slow query logging & re-enabling it once the rotation is complete.

Manual Rotation
To manually rotate slow query logs, we’ll temporarily disable slow query logging, flush slow logs, rename the original file & finally re-enable slow query logging.

get the path to slow query log file

MariaDB [(none)]> show variables like '%slow_query%';
+---------------------+-------------------------------+
| Variable_name | Value |
+---------------------+-------------------------------+
| slow_query_log | ON |
| slow_query_log_file | /var/lib/mysql/mysql-slow.log |
+---------------------+-------------------------------+
2 rows in set (0.00 sec)
temporarily disable slow query logging

MariaDB [(none)]> set global slow_query_log=off;
Query OK, 0 rows affected (0.00 sec)
flush only slow logs

MariaDB [(none)]> flush slow logs;
Query OK, 0 rows affected (0.00 sec)
rename the old log file and or compress it

[email protected]:~# mv /var/lib/mysql/mysql-slow.log /var/lib/mysql/mysql-slow-$(date +%Y-%m-%d).log
[email protected]:~# gzip -c /var/lib/mysql/mysql-slow-$(date +%Y-%m-%d).log > /var/lib/mysql/mysql-slow-$(date +%Y-%m-%d).log.gz
finally, re-enable slow query logging

MariaDB [(none)]> set global slow_query_log=on;
Query OK, 0 rows affected (0.00 sec)

使用 logrotate

使用 logrotate 您可以安全的对 mysql query log 的日志进行切分
logrotate: /etc/logrotate.d/mysql-query

/var/lib/mysql/ubuntu.log {
        daily
        size 1G
        rotate 2
        missingok
        create 640 mysql adm
        compress
        sharedscripts
        postrotate
                test -x /usr/bin/mysqladmin || exit 0
                # If this fails, check debian.conf! 
                MYADMIN="/usr/bin/mysqladmin --defaults-file=/etc/mysql/debian.cnf"
                if [ -z "`$MYADMIN ping 2>/dev/null`" ]; then
                  # Really no mysqld or rather a missing debian-sys-maint user?
                  # If this occurs and is not a error please report a bug.
                  #if ps cax | grep -q mysqld; then
                  if killall -q -s0 -umysql mysqld; then
                    exit 1
                  fi
                else
                  $MYADMIN flush-logs
                fi
        endscript
}

参数                         功能
   compress                     通过gzip 压缩转储以后的日志
   nocompress                   不需要压缩时,用这个参数
   copytruncate                 用于还在打开中的日志文件,把当前日志备份并截断
   nocopytruncate               备份日志文件但是不截断
   create mode owner group      转储文件,使用指定的文件模式创建新的日志文件
   nocreate                     不建立新的日志文件
   delaycompress 和 compress    一起使用时,转储的日志文件到下一次转储时才压缩
   nodelaycompress              覆盖 delaycompress 选项,转储同时压缩。
   errors address               专储时的错误信息发送到指定的Email 地址
   ifempty                      即使是空文件也转储,这个是 logrotate 的缺省选项。
   notifempty                   如果是空文件的话,不转储
   mail address                 把转储的日志文件发送到指定的E-mail 地址
   nomail                       转储时不发送日志文件
   olddir directory             转储后的日志文件放入指定的目录,必须和当前日志文件在同一个文件系统
   noolddir                     转储后的日志文件和当前日志文件放在同一个目录下
   prerotate/endscript          在转储以前需要执行的命令可以放入这个对,这两个关键字必须单独成行
   postrotate/endscript         在转储以后需要执行的命令可以放入这个对,这两个关键字必须单独成行
   daily                        指定转储周期为每天
   weekly                       指定转储周期为每周
   monthly                      指定转储周期为每月
   rotate count                 指定日志文件删除之前转储的次数,0 指没有备份,5 指保留5 个备份
   tabootext [+] list           让logrotate 不转储指定扩展名的文件,缺省的扩展名是:.rpm-orig, .rpmsave, v, 和 ~
   size 1G                    当日志文件到达指定的大小时才转储,Size 可以指定 bytes (缺省)以及KB (sizek)或者MB (sizem).

dateext: archive old log files by adding a date extension using the format YYYYMMDD instead of using a number.
missingok: if a log file is missing, don’t issue an error message
rotate 20: 保存多少个切分文件
notifempty: don’t rotate empty log files
sharedscripts: run prerotate & postrotate scripts only once, no matter how many logs match the wildcard pattern

网址规范化一直是困扰站长以及搜索引擎的一个问题。据估计,网上有10%-30%的URL是内容相同但URL不一样的不规范化网址。

这就造成几个问题。比如:

对站长来说,多个URL存在分散了页面权重,不利于排名。
对搜索引擎来说,浪费资源,浪费带宽。
搜索引擎发现多个网址内容相同时,不会惩罚,而会尽可能找出那个应该是规范化的网址。但程序毕竟只是程序,可能出错,挑出来的可能不是站长想要的那个规范化网址。
网站上网址规范化问题太严重的话,也可能影响收录。一个权重不很高的域名,能收录的总页面数字是有限的。搜索引擎把资源花在收录不规范的网址上,留下给真正不同内容的资源就减少了。

要解决URL规范化问题也有很多选项,比如:

在Google管理员工具中设置带3W和不带3W的,哪一个是规范化版本
使用301转向,把不规范化URL全部转向到规范化URL
确保使用的CMS系统只产生规范化网址
确保网站上所有站内链接都指向规范化网址
在提交给搜索引擎的网站地图中全部指定规范化网址

但这些方法都各有局限。

Google管理员工具不适用于其他搜索引擎
有的站长因为某种原因做不了301转向
CMS系统大部分情况下不受自己控制
内部链接自己可以控制,但其他人链接到自己网站上就不受控制了

总之,虽然有解决方法备选,但网址规范化到目前为止还是个不小的问题。

前几天Google,雅虎,微软共同发布了一个新的标签canonical tag,用于解决网址规范化问题。

简单说,就是在HTML文件的头部加上这样一段代码:

<link rel=”canonical” href=”http://www.example.com/product.php?item=swedish-fish” />

意义就是这个网页的规范化网址应该是:

http://www.example.com/product.php?item=swedish-fish

下面这些URL都可以加上这段代码:

http://www.example.com/product.php?item=swedish-fish&category=gummy-candy

http://www.example.com/product.php?item=swedish-fish&trackingid=1234&sessionid=5678

这些URL的真正规范化网址就都成为:

http://www.example.com/product.php?item=swedish-fish

简单说,这个标签相当是一个页面内的301转向。区别在于用户并不被转向,还是停留在不变网址上,而搜索引擎会把它当作是301转向处理,也就是说把页面链接的权重都集中到代码中指明的规范化网址上。

另外有几个细节站长需要注意:

这个标签只是一种建议或暗示,而不是指令,它不像robots文件那样是个指令。所以搜索引擎会很大程度上考虑这个代码,但并不是百分之百,还会考虑其他情况来判断规范化网址。这也防止站长有可能把网址弄错。
这段代码既可以使用绝对地址,也可以使用相对地址。通常还是建议使用绝对地址比较保险。
指定的规范化网址上的内容,与其他使用这段代码的非规范化网址内容可以有一些不同,不一定完全一样。比如在电子商务网站上有很多按价钱、颜色,、尺寸升降排序,生成的URL全都不一样,但内容大体相同,只有细小区别,就可以使用这个标签。
指定的规范化网址可以是不存在页面,返回404,也可以是还没有被收录的页面。但是不建议这么做,别没事找事。
这个标签适用于同一个域名内,包括二级域名。但不适用于不同域名之间,防止有人劫持。
别把这个标签当救命草,首先还是得把网站结构做好,尽量避免出现URL规范化问题。这只是最后万不得已的方法。

敏感的人大概能从这个新标准里看到建立大量外部链接的机会。

最后提一句,这个标准被3大搜索引擎Google,雅虎,微软同时支持。