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,則加入「軟連結」。 |