Drupal 维护
Drupal 组态设置
drush config-get
Choose a configuration: [0 ] Cancel [1 ] antibot.settings [2 ] automated_cron.settings [3 ] block.block.bannerspace ...
drush config:get system.site
langcode: en uuid: d01d9a08-4a68-87bb-a98f-f21552ec5f2e name: 'Vicsys Systems' mail: slogan: '' page: 403: '' 404: '' front: /home.html ...
uuid
,在组态的结构中主键为 uuid
。drush config:get system.site uuid
page
内的 front
,主键值为 page.front
。drush config:get system.site page.front
drush config-set system.site name 'Vicsys Systems' -y
修改 Performance
中的 Aggregate CSS files
、Aggregate JavaScript files
(<Site>/zh-hant/admin/config/development/performance
)。
drush config-get system.performance
cache: page: max_age: 600 use_internal: false css: preprocess: false gzip: false fast_404: ... js: preprocess: false gzip: false ...
css.preprocess
、js.preprocess
,另外设置值为 Boolean
,需以 0
、1
来设置。drush config:set system.performance css.preprocess 1 -y
drush config:set system.performance js.preprocess 1 -y
Drupal 组态导出及导入
drush config-export (cex)
,config-export
可用缩写 cex
。mkdir /var/www/files/config/all -p
drush config-export --destination=/var/www/files/config/all
导入时可能只需要其中一些配置,而 drush config:import (cim)
会导入所有配置,这不是我们想要的,导入时采用 --partial
参数可允许从来源目录中导入部分配置。
假设要导入站台名称,那么搜索站台名称,得到文件名:/var/www/files/config/all/system.site.yml
。
system.site.yml
)mkdir /var/www/files/config/site -p cp /var/www/files/config/all/system.site.yml /var/www/files/config/site/system.site.yml
drush config:import --partial --source=/var/www/files/config/site --preview=diff (1)
1 | --preview=diff 可得知组态文件跟站台配置有那些不同。 |
导入单一文件时,可运行 Drupal console (drupal
) 的 config:import:single (cis)
来导入,其组态是由导入文件名来决定;如 system.site.yml
是导入至组态 system.site
。
drupal config:import:single --directory=/var/www/files/config/all --file=system.site.yml (1) drupal cis --file=/var/www/files/config/all/system.site.yml (1)
1 | 上面两个指令是相同的。
Drupal 9 会出现下列错误,不过文件会正确导入。
ArgumentCountError: Too few arguments to function Drupal\Core\Config\ConfigImporter::__construct(), 9 |
以 Drupal console 导出单一配置时,依据命令中的参数说明,实测运作方式不如预期!
--directory
无作用,不指定参数时为询问。
drupal config:export:single -h Usage: config:export:single [options] ces Options: --name[=NAME] Configuration name. (multiple values allowed) --directory[=DIRECTORY] Define the export directory to save the configuration output. --module[=MODULE] The Module name. --include-dependencies Export dependencies of the configuration as well. --optional Export config as an optional YAML configuration in your module --remove-uuid If set, the configuration will be exported without uuid key. --remove-config-hash If set, the configuration will be exported without the default site hash key.
system.performance
,把全部的参数填入 (除了 --include-dependencies
)drupal config:export:single --name=system.performance --directory=dummy --module=system --optional --remove-uuid --remove-config-hash
找不到有 dummy
的文件夹,--directory
并无作用。
--optional
会固定输出至 core/modules/system/config/optional
。Configuration(s) exported successfully - core/modules/system/config/optional/system.performance.yml
--optional
则会讯问:drupal config:export:single --name=system.performance --module=system --remove-uuid --remove-config-hash
Export config in module as an optional configuration (yes/no) [yes]: > no Configuration(s) exported successfully - core/modules/system/config/install/system.performance.yml (1)
1 | 无 optional 则输出至 core/modules/system/config/install |
上述的 system.performance.yml
内容都是 YAML 格式,跟 drush config-export
导出的文件大致相同,文件内容缺少 default_config_hash
及 uuid
。
default_config_hash
还是可以正确导入:drupal config:import:single --file=core/modules/system/config/optional/system.performance.yml
[OK] Configuration(s) "system.performance", has been imported successfully.
drush config-get system.performance cache: page: max_age: 600 use_internal: false css: preprocess: false gzip: false ...
image.settings
导出,其中的 --module=system
不需要更改。printf '%s\n' no no | drupal config:export:single --name=image.settings --module=system --optional
Do you want to remove the uuid from this export? (yes/no) [yes]: > Do you want to remove the default site hash from this export? (yes/no) [yes]: > Configuration(s) exported successfully - core/modules/system/config/optional/image.settings.yml
default_config_hash
的 image.settings.yml
拷贝成 system.performance.yml
,再导入,会发生什么?cp core/modules/system/config/optional/image.settings.yml system.performance.yml
drupal config:import:single --file=system.performance.yml
[OK] Configuration(s) "system.performance", has been imported successfully.
drush config-get system.performance _core: default_config_hash: k-yDFHbqNfpe-Srg4sdCSqaosCl2D8uwyEY5esF8gEw preview_image: core/modules/image/sample.png allow_insecure_derivatives: false suppress_itok_output: false
结果是 system.performance
是依据 system.performance.yml
文件内容来变更,并不依据 default_config_hash
。
system.site
的组态比较特殊,system.site.yml
文件内必须要 uuid
,而且必须跟网站的 uuid
相同。否则会出现下列错误:
[ERROR] An error occurred while trying to write the config file: "commands.config.import.messages.import-fail Site UUID in source storage does not match the target storage."
解决方式是把 UUID 调整一致才能导入。
可将组态档中存在的 uuid 覆盖当前站台的 uuid。
drush config-get system.site uuid
drush config-set system.site uuid 'd01d9a08-4a68-87bb-a98f-f21552ec5f2e' -y
Configuration Split
导出模块组态或翻译,采用 Configuration Split
的原因在于时能选取某些模块或项目,不像 drush config-export
只能全部导出。
modi config_split
- <site>/admin/config/development/configuration/config-split
- Configuration Split setting
-
+Add Configuration Split setting
- Add configuration split setting
-
- Label
-
csbak
- Folder
-
/var/www/files/config/split
- COMPLETE SPLIT
-
选取要备份的模块。 (采用这个比较容易理解)
- Configuration items
-
选取要备份的模块项目。
# 找出命令是什么
drush | grep config-split
# config-split:
# config-split:export (csex) Export only split configuration to a directory.
# config-split:import (csim) Import only config from a split.
mkdir /var/www/files/config/split -p
# 导出
drush csex csbak -y
# 导入
drush csim csbak -y
建置测试环境
- 建置测试(备份)环境问题分析与解决
-
-
建置环境需要测试,Drupal 安装组件或更新时有时会出状况。
drupal 在测试前,先clone-site
from drupal to newsite,有问题回复clone-site
from newsite to drupal。 -
删除 newsite 则运行
drop-site
newsite。 -
Apache alias 命名
测试站台命名:try1 ~ try9
范例站台命名:demo1 ~ demo9
备份站台命名:bak1 ~ bak9
Apache trySites.confAlias /try1 /var/www/try1 ... Alias /try9 /var/www/try9 Alias /demo1 /var/www/bak1 ... Alias /demo9 /var/www/bak9 Alias /bak1 /var/www/demo1 ... Alias /bak9 /var/www/demo9 # 开放 www <Directory /var/www> Options FollowSymLinks AllowOverride All Require ip 192.168.1.1/255.255.255.0 </Directory>
-
拷贝站台
clone-site [OPTION] [<remote>:]<source> [<destination>] options: -y Never prompt
clone-site drupal try1
clone-site 192.168.1.1:druapl
- MySQL 不可小于远程站台的版本,否则会出现下列错误
-
ERROR 1118 (42000) at line 259: The size of BLOB/TEXT data inserted in one transaction is greater than 10% of redo log size. Increase the redo log size using innodb_log_file_size.
bind "set disable-completion on"
bash -c "cat > /var/www/bin/clone-site" << "EOF2"
#!/bin/bash
usage="Usage: ${0##*/} [OPTION] [<remote>:]<source> [<destination>]
Clone site
options:
-y Never prompt"
Prompt=1
POSITIONAL=()
while (( "$#" )); do
case "$1" in
-h|--h*) echo "$usage"; exit 1;;
-y|--y) Prompt=0; shift;;
*)
POSITIONAL+=("$1") # save it in an array for later
shift;;
esac
done
set -- "${POSITIONAL[@]}" # restore positional parameters
if [[ $1 = *:* ]]; then
remoteHost=${1%%:*}
remoteHost=${remoteHost,,}
sourceSite=${1##*:}
if [[ -z $sourceSite ]]; then
echo "$usage"
exit 1
fi
if [[ -z $2 ]]; then
localSite=$sourceSite
else
localSite=$2
fi
sourceLocation=$remoteHost:$sourceSite
# Will continue when resolveip fails
if [[ $remoteHost = ${HOSTNAME,,} ]] || [[ $HOSTNAME = $(resolveip -s $remoteHost) ]]; then
echo "Error: The remote host is the current host!" >&2
exit 1
fi
else
if [[ -z $1 ]] || [[ -z $2 ]]; then
echo "$usage"
exit 1
fi
if [[ $1 = $2 ]]; then
echo "Error: The source destination is the same!" >&2
exit 1
fi
sourceSite=$1
localSite=$2
sourceLocation=$sourceSite
fi
if [[ $Prompt -eq 1 ]]; then
read -p "clone-site $sourceLocation to $localSite? [Y/n] " yn
yn=${yn:-y}
if [[ $yn != Y ]] && [[ $yn != y ]]; then
exit 1
fi
fi
if [[ -z $remoteHost ]]; then
sudo sh -c "chown -R www-data:www-data /var/www/$localSite; chmod -Rf 774 /var/www/$localSite" 2> /dev/null
fi
# Exit immediately on error
set -e
echo rsync $sourceLocation to $localSite
if [[ -n $remoteHost ]]; then
sudo rsync -az --info=progress2 root@$remoteHost:/var/www/$sourceSite/ \
--delete --chmod=775 --chown=www-data:www-data /var/www/$localSite
echo Export soruce database $sourceLocation
ssh root@$remoteHost "mysqldump -uroot -p$mysqlpw --host=localhost --port=3306 $sourceSite" > /var/www/$localSite/_srcdb.sql
else
sudo rsync -a --chown=www-data:www-data --chmod=775 --info=progress2 --delete /var/www/$sourceSite/ /var/www/$localSite
echo Export soruce database $sourceLocation
mysqldump -uroot -p$mysqlpw --host=localhost --port=3306 $sourceSite > /var/www/$localSite/_srcdb.sql
fi
NC='\033[0m' # No Color
YELLOW='\033[1;33m'
echo -e "${YELLOW}***Now you can maintain the original site.***${NC}"
echo Create database $localSite
mysql -uroot -p$mysqlpw --host=localhost --port=3306 --protocol=tcp -n<<EOF
drop database if exists $localSite;
create database $localSite;
grant all privileges on $localSite.* to '$localSite'@'localhost' identified by '$webdbpw';
use mysql;
update user set plugin='mysql_native_password' where user='$localSite';
flush privileges;
EOF
echo Import table $localSite
mysql -u$localSite -p$webdbpw --host=localhost --port=3306 $localSite < /var/www/$localSite/_srcdb.sql
echo rm /var/www/$localSite/_srcdb.sql
if [[ $sourceSite != $localSite ]]; then
echo -e "${YELLOW}"
if [ -f "/var/www/$localSite/sites/default/settings.php" ]; then
echo change settings.php
src="\n *\$databases *\[ *'default' *\] *\[ *'default' *\] *= *array *(\n *'database' *=> *'[0-9a-zA-Z]\+' *, *\n *'username' *=> *'[0-9a-zA-Z]\+' *, *"
trs="\n\$databases\['default'\]\['default'\] = array (\n 'database' => '$localSite',\n 'username' => '$localSite',"
sed -z -i "s/$src/$trs/" /var/www/$localSite/sites/default/settings.php
sudo chown www-data:www-data /var/www/$localSite/sites/default/settings.php
dbProfile=$(sed -n "/\$databases\['default'\]\['default'\] = array (/ {N;/'database' => '$localSite'/!q;N;/'username' => '$localSite'/!q;N;p}" /var/www/$localSite/sites/default/settings.php)
if [[ -z $dbProfile ]]; then
echo "*** Can not find database parameters! ***"
echo $(grep "^ *\$databases\[ *'default' *\] *\[ *'default' *\] *= *array *(" -A3 /var/www/$localSite/sites/default/settings.php)
else
echo $dbProfile
cd /var/www/$localSite
drush cr
fi
else
echo "*** Can not find /var/www/$localSite/sites/default/settings.php! ***"
fi
fi
EOF2
bind "set disable-completion off"
sudo chmod +x /var/www/bin/clone-site
删除站台
bind "set disable-completion on"
bash -c "cat > /var/www/bin/drop-site" << "EOF2"
#!/bin/bash
tab=' '
nl='
'
IFS=" $tab$nl"
usage="Usage: ${0##*/} [OPTION] site
Drop site
options:
-y Never prompt"
Prompt=1
POSITIONAL=()
while (( "$#" )); do
case "$1" in
-h|--h*) echo "$usage"; exit 1;;
-y|--y) Prompt=0; shift;;
*)
POSITIONAL+=("$1") # save it in an array for later
shift;;
esac
done
set -- "${POSITIONAL[@]}" # restore positional parameters
if [ "$1" = "" ]; then
echo "$usage"
exit 1
fi
if [ $Prompt -eq 1 ]; then
read -p "drop-site $1? [Y/n] " yn
yn=${yn:-y}
if [ "$yn" != "Y" ] && [ "$yn" != "y" ]; then
exit 1
fi
fi
echo rm $1
sudo rm /var/www/$1 -r
echo Drop database $1
mysql -uroot -p$mysqlpw --host=localhost --port=3306 --protocol=tcp -N<<EOF
drop database if exists $1;
drop user if exists '$1'@'localhost';
flush privileges;
EOF
EOF2
bind "set disable-completion off"
sudo chmod +x /var/www/bin/drop-site
站台重建
站台更新失败,或者站台在更新 (含内核) 模块之后,可能会发现某个模块的运作不如预期,高度怀疑是因为模块出错。
若模块的运作不如预期,先运行 drush cr 再次检查避免误判。
|
-
创建新站台,安装跟原站台一样模块及版本,并激活跟原站台一样模块。
运行modc-site
比对站台模块。注:该脚本亦可比对测试站台安装了那些新模块。 -
测试新站台的运作是否合乎预期。
-
将原始数据 以
clone-db
导入至新新站台。
site=try1
refsite=drupal
diff /var/www/$site /var/www/$refsite \
-qr --exclude="*.yml" --exclude="*.po" \
| sort > _diff.txt (1)
grep -v -E "files/js|files/css|files/color|default/files: config|files/languages: |default/settings.php" \
_diff.txt (2)
grep ".php" _diff.txt (3)
1 | 先创建 _diff.txt |
2 | 比对文件 (排除已知不同文件)。 |
3 | 只比对 .php |
比对站台模块
bind "set disable-completion on"
bash -c "cat > /var/www/bin/modc-site" << "EOF"
#!/bin/bash -e
tab=' '
nl='
'
IFS=" $tab$nl"
usage="Usage: ${0##*/} [OPTION] source target
Compare modules
options:
-c, --cr Clear cache"
clearCache=0
POSITIONAL=()
while (( "$#" )); do
case "$1" in
-h|--h*) echo "$usage"; exit 1;;
-c|--cr) clearCache=1; shift;;
*)
POSITIONAL+=("$1") # save it in an array for later
shift;;
esac
done
set -- "${POSITIONAL[@]}" # restore positional parameters
if [ -z "$1" ] || [ -z "$2" ]; then
echo "$usage"
exit 1
fi
if [ "$1" = "$2" ]; then
echo "Error: The source target is the same!" >&2
exit 1
fi
fileName=_Module.txt
cd /var/www/$1
if [ $clearCache -eq 1 ]; then
drush cr
fi
drush pm-list --fields display_name,version,status --type=module > $fileName
cd /var/www/$2
if [ $clearCache -eq 1 ]; then
drush cr
fi
drush pm-list --fields display_name,version,status --type=module > $fileName
diff -y <(sed 's/\([ -]\)*/\1/g' /var/www/$1/$fileName | fold -s -w80) \
<(sed 's/\([ -]\)*/\1/g' /var/www/$2/$fileName | fold -s -w80) -W 160 | grep '[<|>]'
rm /var/www/$1/$fileName
rm /var/www/$2/$fileName
EOF
bind "set disable-completion off"
sudo chmod +x /var/www/bin/modc-site
拷贝站台数据库
bind "set disable-completion on"
bash -c "cat > /var/www/bin/clone-db" << "EOF2"
#!/bin/bash -e
tab=' '
nl='
'
IFS=" $tab$nl"
usage="Usage: ${0##*/} [OPTION] source target
Clone database
options:
-y Never prompt"
Prompt=1
POSITIONAL=()
while (( "$#" )); do
case "$1" in
-h|--h*) echo "$usage"; exit 1;;
-y|--y) Prompt=0; shift;;
*)
POSITIONAL+=("$1") # save it in an array for later
shift;;
esac
done
set -- "${POSITIONAL[@]}" # restore positional parameters
if [ "$1" = "" ] || [ "$2" = "" ]; then
echo "$usage"
exit 1
fi
if [ "$1" = "$2" ]; then
echo "Error: The source target is the same!" >&2
exit 1
fi
if [ $Prompt -eq 1 ]; then
read -p "clone-db $1 to $2? [Y/n] " yn
yn=${yn:-y}
if [ "$yn" != "Y" ] && [ "$yn" != "y" ]; then
exit 1
fi
fi
echo mysqldump $1
mysqldump -uroot -p$mysqlpw --host=localhost --port=3306 $1 > /var/www/$2/_srcdb.sql
echo create database $2
mysql -uroot -p$mysqlpw --host=localhost --port=3306 --protocol=tcp -n<<EOF
drop database if exists $2;
create database $2;
grant all privileges on $2.* to '$2'@'localhost' identified by '$webdbpw';
use mysql;
update user set plugin='mysql_native_password' where user='$2';
flush privileges;
EOF
echo Import table $2
mysql -u$2 -p$webdbpw --host=localhost --port=3306 $2 < /var/www/$2/_srcdb.sql
rm /var/www/$2/_srcdb.sql
cd /var/www/$2
drush cr
EOF2
bind "set disable-completion off"
sudo chmod +x /var/www/bin/clone-db
Drupal 8 升级至 Drupal 9
- 先在测试站台准备升级(重要)
-
安装 upgrade_status
clone-site drupal try9 composer require drupal/upgrade_status (1) drush en upgrade_status drush cr
1 安装 Upgrade Status 可事先检查兼容情况。但实际的站台升级又可能因为 upgrade_status
造成升级失败,upgrade_status
仅可用来检查兼容性,依据兼容性调整原始站台,当然若不放心可clone-site
原始站台至另一站台再调整。进入 <site>/admin/reports/upgrade-status 检查一下情况。When using MariaDB, minimum version is 10.3.7 Alternatively, install the MariaDB 10.1 driver for Drupal 9 for now.
MariaDB 最低需求版本为 10.3.7 可升级至 10.3.27 或者安装 MariaDB 10.1 驱动程序。
# 先升级 composer.json
composer require drupal/core-recommended:^9.0.0 drupal/core-composer-scaffold:^9.0.0 \
drupal/core-project-message:^9.0.0 --update-with-dependencies --no-update
# ./composer.json has been updated
# If you have drupal/core-dev installed.
# composer require drupal/core-dev:^9.0.0 --dev --update-with-dependencies --no-update
composer update
- 若需要安装 MariaDB 10.1 驱动程序
-
安装驱动程序
composer require drupal/mysql56
在 sites/default/settings.php 加入下列$databases['default']['default']['namespace'] = 'Drupal\\Driver\\Database\\mysql';
drush updatedb (1) drush cr chwww .
1 | 注意如果出现红底消息 [error] * The database server version x.x.x is less than the minimum required version x.x.x. 表示有误,千万别继续运行。 |
- Reference
-
Upgrading from Drupal 8 to Drupal 9 (or higher) | Upgrading Drupal | Drupal guide on Drupal.org
Upgrading Drupal 8 to Drupal 9: The real-world experience | Touch4IT - Drupal core 9.0.9/9.1.0 有下列错误
-
drupal site:mode dev
PHP Fatal error: Uncaught Error: Call to undefined method Drupal\Core\DrupalKernel::prepareLegacyRequest() in /var/www/try9/vendor/drupal/console/src/Utils/DrupalApi.php:266
在 vendor/drupal/console/src/Utils/DrupalApi.php:266 删除该行原代码$kernel->prepareLegacyRequest($request);
Drupal patch
当发现某个模块的运作不如预期,除了 Google 之外,可进入 https://www.drupal.org/project/<Machine name>
,如 ds (Display Suite) 为
https://www.drupal.org/project/ds 按下网页中的 Bug report
(Issues for Display Suite | Drupal.org )。
#9 2887778-9.patch #3 ds-2887778-3-D8.patch (1)
1 | 有点奇怪,激活 NoScript 有 ds-2887778-3-D8.patch。 |
Needs review Project: Display Suite Version: 8.x-4.x-dev (1)
1 | 在 8.x-4.x-dev 版本中尚未修正,安装 8.x-4.x-dev 也无作用。 |
composer show | grep drupal/ds
# drupal/ds 3.9.0
mkdir -p /var/www/files/patch (1)
wget -P /var/www/files/patch "https://www.drupal.org/files/issues/2018-08-27/2887778-9.patch"
1 | 创建 patch 目录保留 patch 文件及被 patch 的文件,当下次更新时,若不正确可试着修改。 |
--- ds.module | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/ds.module b/ds.module (1) index 8dc1de5d..0d03e4c6 100644 --- a/ds.module +++ b/ds.module ...
1 | 得知是 patch ds.module |
cp modules/contrib/ds/ds.module /var/www/files/patch/ds.module.src (1)
1 | 重要!重新 patch 时,有源文件案可随时回复或测试。 |
git apply /var/www/files/patch/2887778-9.patch --directory modules/contrib/ds
# warning: modules/contrib/ds/ds.module has type 100755, expected 100644
# 上述有警告, 实际上已运行 patch。
# 修改模块应重建缓存
drush cr
# 回复 patch
# git apply /var/www/files/patch/2887778-9.patch --directory modules/contrib/ds --reverse
# 回复 patch
git apply /var/www/files/patch/2887778-9.patch --directory modules/contrib/ds --reverse
wget -P /var/www/files/patch "https://www.drupal.org/files/issues/ds-2887778-3-D8.patch"
git apply /var/www/files/patch/ds-2887778-3-D8.patch --directory modules/contrib/ds
# error: patch fragment without header at line 5: @@ -14,13 +14,13 @@
# git 出错改用 patch
patch -i /var/www/files/patch/ds-2887778-3-D8.patch modules/contrib/ds/ds.module
# patching file modules/contrib/ds/ds.module
# patch 结果无误
drush cr
#重建缓存后测试,不正确。
# 运行 2887778-9.patch
patch -i /var/www/files/patch/2887778-9.patch modules/contrib/ds/ds.module
# patching file modules/contrib/ds/ds.module
# Hunk #1 succeeded at 635 (offset 2 lines).
drush cr
#重建缓存后测试,结果正确。
# 保留本次修正的结果
cp modules/contrib/ds/ds.module /var/www/files/patch/ds.module.patched
cp /var/www/files/patch/ds.module.src modules/contrib/ds/ds.module
git apply /var/www/files/patch/2887778-9.patch --directory modules/contrib/ds
drush cr (1)
cp /var/www/files/patch/ds.module.src modules/contrib/ds/ds.module
patch -i /var/www/files/patch/ds-2887778-3-D8.patch modules/contrib/ds/ds.module (2)
patch -i /var/www/files/patch/2887778-9.patch modules/contrib/ds/ds.module
drush cr (3)
1 | 重建缓存后测试,确定不正确。 |
2 | 再次 patch 两个文件 |
3 | 重建缓存后测试,确定正确,要 patch 两个文件。 |
Admin toolbar z-index
由于网页的 z-index 必须为 1031, 而 Druapl 的 Admin toolbar 管理接口为 502,网页会覆盖 Admin toolbar,将 Admin toolbar 的 z-index 修改该为 1032。
/* Layer the bar just above the trays and above contextual link triggers. */
.toolbar-oriented .toolbar-bar {
z-index: 502; (1)
}
/* Layer the bar just above the trays and above contextual link triggers. */
/*** MY-PATCH 502 to 1032 ***/
.toolbar-oriented .toolbar-bar {
z-index: 1032;
}
# 先备份源文件案
cp core/modules/toolbar/css/toolbar.module.css /var/www/files/patch/toolbar.module.css.src
nano core/modules/toolbar/css/toolbar.module.css
# 502 修改为 1032
# 产生 patch
diff -u /var/www/files/patch/toolbar.module.css.src \
core/modules/toolbar/css/toolbar.module.css \
> /var/www/files/patch/toolbar.module.css.patch
# 备份本次修改结果
cp core/modules/toolbar/css/toolbar.module.css /var/www/files/patch/toolbar.module.css.patched
# 下次更新时, 再次运行
patch -i /var/www/files/patch/toolbar.module.css.patch core/modules/toolbar/css/toolbar.module.css
# 检查 .z-index
grep -A 4 'Layer the bar just above the trays and above contextual link triggers' \
core/modules/toolbar/css/toolbar.module.css
重导网页 (Redirect page)
401 Authorization failed 授权失败。用户输入的帐号密码未得到授权。 403 Forbidden 访问控制机制拒绝用户的请求,不可读取该文件。 404 File not found 被要求的网页不存在于这个服务器上,找不到文件。 500 Internal Server Error 服务器内部错误;可能是网站服务器出错。 501 Not Implemented 服务器不了解数据传递的方式。 503 Service Unavailable 服务器暂停服务
禁止进入管理页面
由 Durpal 正规将 403 转成 404,网页虽然可显示成 404 的样式,但状态码还是 403,只能由 apache 重导至 php,再由 php 改变状态码为 404。
<VirtualHost *:80> DocumentRoot /var/www/drupal RewriteEngine on ErrorDocument 404 /html/404.php (1) ErrorDocument 403 /html/404.php (1) RewriteCond expr "%{REMOTE_ADDR} -ipmatch '192.168.1.0/24'" (2) RewriteRule .? - [L] (2) RewriteCond %{REQUEST_URI} (/[uU][sS][eE][rR]|/[aA][dD][mM][iI][nN]) (3) RewriteRule .? - [L,R=404] (3) <FilesMatch "(install|update).php"> (4) Order deny,allow deny from all Allow from 192.168.1.0/24 (5) </FilesMatch> <Directory /var/www/drupal> AllowOverride None Include /var/www/drupal/.htaccess </Directory> </VirtualHost>
1 | 404 及 403 网页为 /var/www/drupal/html/404.php |
2 | 允许局域网路进入 user 或 admin。 |
3 | 若不为局域网路则重导至 404。 |
4 | 若不为局域网路,禁止进入 install.php update.php …,apache 会重导至 403,不过有语言 url 就破功了。 |
5 | 若为局域网路,可进入「禁止」网页,不过,如果采用 composer drush 实际上并不需要由网页来处理。 |
Require ip 192.168.1.1 Require ip 192.168.1.0/255.255.255.0 Require ip 192.168.1.0/24
由于 drupal 并不允许在其他路径中运行自定的 php,需修改根目录中的 .htaccess 文件。
- 解决无法在 Drupal 目录中运行自定的 php
-
# For security reasons, deny access to other PHP files on public sites. # Note: The following URI conditions are not anchored at the start (^), # because Drupal may be located in a subdirectory. To further improve # security, you can replace '!/' with '!^/'. # Allow access to PHP files in /core (like authorize.php or install.php): RewriteCond %{REQUEST_URI} !/core/[^/]*\.php$ # Allow access to test-specific PHP files: RewriteCond %{REQUEST_URI} !/core/modules/system/tests/https?.php # Allow access to Statistics module's custom front controller. # Copy and adapt this rule to directly execute PHP files in contributed or # custom modules or to run another PHP application in the same directory. RewriteCond %{REQUEST_URI} !/core/modules/statistics/statistics.php$ ### MY-PATCH Allow for my_custom_directory folder to run php ### (1) RewriteCond %{REQUEST_URI} !/html/[^/]*\.php$ (1)
1 加入允许 php 规则。
# 先备份源文件案
cp .htaccess /var/www/files/patch/.htaccess.src
nano .htaccess
# 加入允许 php 规则。
# 产生 patch
diff -u /var/www/files/patch/.htaccess.src \
.htaccess \
> /var/www/files/patch/.htaccess.patch
# 备份本次修改结果
cp .htaccess /var/www/files/patch/.htaccess.patched
# 下次 drupal 更新时, 再次运行
patch -i /var/www/files/patch/.htaccess.patch .htaccess
# 检查结果
grep -A 5 '# custom modules or to run another PHP application in the same directory.' \
.htaccess
<?php
http_response_code(404); (1)
$lant='en';
$url=$_SERVER['REQUEST_URI'];
if (preg_match('~^/zh-hant(?:/|$)~i', $url)) {
$lang='zh-TW';
} elseif (preg_match('~^/zh-hans(?:/|$)~i', $url)) {
$lang='zh-CN';
} else {
$lang=strtok($_SERVER['HTTP_ACCEPT_LANGUAGE'], ',');
}
switch ($lang) {
case 'zh-TW':
include '404_tw.html'; (2)
break;
case 'zh-CN':
include '404_cn.html';
break;
default:
include '404_en.html';
}
1 | 一律回传 404 状态码给浏览器,跟网页一致 (403 也回传 404)。 |
2 | 按 drupal.conf 中的 DocumentRoot 及 ErrorDocument 的路径,/var/www/drupal/html/404_tw.html 为正体中文的 404 网页。 |
那么要写 404 网页?不用!只需产生网站的 404 网页即可。
wget --content-on-error <site>/zh-hant/notexists -O /var/www/drupal/html/404_tw.html wget --content-on-error <site>/zh-hans/notexists -O /var/www/drupal/html/404_cn.html wget --content-on-error <site>/en/notexists -O /var/www/drupal/html/404_en.html
维护页面
当网站在「维护」时,不进实际网站页面,其原因在于维护时会更新文件及数据库,若再进入网站页面会造成不预期的结果,可能进入 install.php 的页面,比较理想的方式是由 Apache 重导至维护页面 (不进入实际网站)。
<VirtualHost *:80> DocumentRoot /var/www/files/site/html (1) RewriteEngine on RewriteCond %{REQUEST_URI} !=/favicon.ico (2) ErrorDocument 503 /503.php (3) RewriteCond %{REQUEST_URI} !/503.php$ [NC] (4) RewriteRule .* - [R=503,L] (5) </VirtualHost>
1 | 维护站台的根目录是在 /var/www/files/site/html 。 |
2 | 允许读取 favicon.ico。如果 url 不为 favicon.ico,进行后续规则,另一说法是如果 url 为 favicon.ico,则直接读取。 |
3 | 维护页面采用 php 来实作具弹性。 |
4 | 如果 url 为 503.php,则直接读取,503.php 要跟 ErrorDocument 一样,不一样会出现 Service Unavailable。 |
5 | 不为 503.php 则重导 503。 |
<?php
$lant='en';
$url=$_SERVER['REQUEST_URI'];
if (preg_match('~^/zh-hant(?:/|$)~i', $url)) {
$lang='zh-TW'; (1)
} elseif (preg_match('~^/zh-hans(?:/|$)~i', $url)) {
$lang='zh-CN'; (2)
} else {
$lang=strtok($_SERVER['HTTP_ACCEPT_LANGUAGE'], ','); (3)
}
switch ($lang) {
case 'zh-TW':
include '503_tw.html'; (4)
break;
case 'zh-CN':
include '503_cn.html';
break;
default:
include '503_en.html';
}
1 | 网址为 <site>\zh-hant 则为 zh-TW。 |
2 | 网址为 <site>\zh-hans 则为 zh-CN。 |
3 | 其他情况,取浏览器的语言。 |
4 | 按 drupal503.conf 中的 DocumentRoot,则 /var/www/files/site/html/503_tw.html 为正体中文的 503 网页。 |
那么要写 503 网页?不用!只需产生网站的 503 网页即可。
# 设置网站维护 drush state:set system.maintenance_mode 1 --input-format=integer drush cr wget --content-on-error <site>/zh-hant/ -O /var/www/files/site/html/503_tw.html wget --content-on-error <site>/zh-hans/ -O /var/www/files/site/html/503_cn.html wget --content-on-error <site>/en/ -O /var/www/files/site/html/503_en.html # 回复正常 drush state:set system.maintenance_mode 0 --input-format=integer drush cr
不过,由于「维护网页」并未由 Drupal 提供 css,需要将 css 改成由网页提供。
<!DOCTYPE html>
<html lang="zh-hant" dir="ltr"
prefix="content: http://purl.org/rss/1.0/modules/content/ dc: http://purl.org/dc/terms/ foaf: http://xmlns.com/foaf/0.1/ og: http://ogp.me/ns# rdfs: http://www.w3.org/2000/01/rdf-schema# schema: http://schema.org/ sioc: http://rdfs.org/sioc/ns# sioct: http://rdfs.org/sioc/types# skos: http://www.w3.org/2004/02/skos/core# xsd: http://www.w3.org/2001/XMLSchema# ">
<head>
<meta charset="utf-8" />
<meta name="MobileOptimized" content="width" />
<meta name="HandheldFriendly" content="true" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="x-ua-compatible" content="ie=edge" />
<link rel="shortcut icon" href="/favicon.ico" type="image/vnd.microsoft.icon" />
<title>网站正在进行维护 | 我的网站</title>
<style type="text/css">
body {
font-family: helvetica, arial, sans-serif;
font-size: 16px;
}
#maintenance-page {
margin-top: 40px;
border: 0px;
width: 800px;
margin-left: auto;
margin-right: auto;
}
</style>
</head>
<body>
<div id="maintenance-page">
<strong>
<span style="color: #9d408d">我的网站</span>
</strong>
<section>
<h1>网站正在进行维护</h1>
我的网站 正在维护中,很快就会回来,请稍候。
</section>
</div>
</body>
</html>
sudo a2dissite drupal sudo a2ensite drupal503 sudo service apache2 reload
sudo a2dissite drupal503 sudo a2ensite drupal sudo service apache2 reload
Xdebug
sudo apt install php-xdebug (1)
find /etc/php -iname '*xdebug.ini' | sort (2)
find /usr/lib/php -iname 'xdebug.so' (3)
1 | 各种不同的系统及版本可参阅 Xdebug: Documentation > Installation 。 |
2 | 安装后 php 各版本内有 xdebug.ini 不过,还是要自行设置,可参阅 Xdebug: Documentation > All settings 。 |
3 | 有不少以日期为目录的版本,但 php 7.3 只有 /usr/lib/php/20180731/xdebug.so (版本 3.0.2) 能正常运行。 |
sudo bash -c 'cat > /etc/php/7.3/mods-available/xdebug.ini' << 'EOF'
zend_extension=/usr/lib/php/20180731/xdebug.so
xdebug.mode=debug (1)
xdebug.discover_client_host=1 (2)
# xdebug.client_host=192.168.0.1
xdebug.client_port=9000
xdebug.start_with_request=yes
EOF
1 | xdebug.mode=debug 激活调试,xdebug.mode=off 取消调试。 |
2 | 如果 PHP / Xdebug 在同一子网中的另一台主机上运行,并且您的浏览器与 IDE 在同一主机上运行,可将 xdebug.discover_client_host 设置为 1,或者设置 xdebug.client_host=192.168.0.1 指定用户计算机 IP。 |
cd ~ (1)
echo "<?php phpinfo();" > phpinfo.php
cat > debug.php << 'EOF'
<?php
$myvar1 = 1;
$myvar2 = 2;
echo $myvar1.' '.$myvar2;
EOF
# sudo service nginx stop
# sudo service apache2 stop
sudo php -S 0.0.0.0:3000 (2)
1 | 范例为家目录。 |
2 | 运行 PHP 内置的 Web server。 |
进入 http://<YourSite>:3000/phpinfo.php 网页,搜索 xdebug
如果无误会看到下列图例。
Visual Studio Code 设置 Xdebug 调试
VSCODE 先安装 PHP Debug 。
在 Windows 的「资源管理器」运行「以 Code 打开」网站文件夹,该目录即为 Samba 的分享文件夹。
VSCODE 会将该文件夹作为 工作区 (workspace)。
若没有「以 Code 打开」则先移除 VSCODE 再重新安装 (重新安装时所有的 Extensions 会保留),在安装画面会有下列选项:
-
将「以 Code 打开」动作加入 Windows 资源管理器目录的操作功能表中
在 VSCOD 的菜单 (menu) 按下 Select Environment
选 (输入) PHP
,VSCOD 会在 工作区
中创建一个子目录
.vscode
及在子目录中创建文件 launch.json
。
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Listen for XDebug",
"type": "php",
"request": "launch",
"port": 9000,
"pathMappings": { (1)
"/home/ubuntu": "${workspaceRoot}",
}
},
{
"name": "Launch currently open script",
"type": "php",
"request": "launch",
"program": "${file}",
"cwd": "${fileDirname}",
"port": 9000
}
]
}
1 | 加入 pathMappings 的设置,其他为原始内容,pathMappings 的格式为 主机路径 对应 本机路径 。主机路径 很明确就是 Linux 的文件路径如 /var/wwww/drupal、/home/ubuntu,而 本机路径 采用变量 ${workspaceRoot} 这表示需将调试的网站文件夹「以 Code 打开」。 |
- 浏览网页时会在运行 PHP Web server 的 CLI 会看到下列消息
-
Xdebug: [Step Debug] Could not connect to debugging client. Tried: <YourSite>:9000 (from REMOTE_ADDR HTTP header), localhost:9000 (fallback through xdebug.client_host/xdebug.client_port) :-(
这表示客户端没有启动调试。
VSCODE 运行调试,在菜单 (menu) 按下
再次浏览网页 http://<YourSite>:3000/debug.php,应该就没有上述消息了,这也表示 Xdebug 已建置完成了。
如果中断点无效,可能是因为 pathMappings
没设置正确,重设置后,在 VSCODE 的菜单按下 即可,不需要去重启 PHP Web server。
由于 VSCODE 并不知道 Druapl 的 .module
也是 PHP 文件,在 VSCODE 中打开 .module
文件后按下
Ctrl+Shift+p 后输入 change language mode
,再选 Configure File Association for '.module'…
最后输入 PHP
。
VSCODE 会将设置档保存在 %USERPROFILE%\AppData\Roaming\Code\User\settings.json,可将 settings.json 移至工作区内的 .vscode 子目录。
停用 Xdebug
看看 Xdebug 配置了那些文件
/etc/php/7.3/apache2/conf.d/20-xdebug.ini (1) /etc/php/7.3/cli/conf.d/20-xdebug.ini (1) /etc/php/7.3/fpm/conf.d/20-xdebug.ini (1) /etc/php/7.3/mods-available/xdebug.ini
1 | 这些文件是是以「软链接」连接至 mods-available/xdebug.ini 可以删除它,或者用 phpdismod 。 |
sudo phpdismod xdebug
sudo service php7.3-fpm restart
sudo netstat -tlpn
# 确定已关闭 PHP Web server 再重启 Web 服务器
# sudo service nginx start
# sudo service apache2 start
sudo phpenmod xdebug (1)
sudo ln -s /etc/php/7.3/mods-available/xdebug.ini /etc/php/7.3/cli/conf.d/20-xdebug.ini (2)
sudo service php7.3-fpm restart
1 | 激活所有 Xdebug |
2 | 或者您可以只在 CLI 启动 Xdebug,则加入「软链接」。 |