作为一个十多年的Drupal用户,在接触百家号/公众号/简书后,琢磨各家之长,改造了一下自己的网站,使其具有图文混排、所见即所得、封面图、水印、Markdown及语法高亮等功能。
本文讲述搭建过程:先用脚本全自动安装/设置一个基本的Drupal8站点;再手动地稍加配置,使其具有百家号的效果;进一步地配置,达到公众号和简书的效果。
广告:本文高度浓缩。全自动安装LAMP/LEMP及Drupal,未见有人做到这么完整。再加上百家号/公众号/简书效果,以及响应式网页,其实可以作为几篇文章。考虑到看官时间宝贵,我就长话短说多合一了。
准备工作
本文在Debian系的Linux(Debian9/8,Ubuntu17)上测试通过。对Redhat系的(比如CentOS),要对apt包(用yum)稍加改造。
先准备一个干净的系统:只需要基本系统、SSH Server。GUI不是必须的。
安装sudo,并把自己加入sudo组。(Ubuntu上不需要这一步,安装时创建的账号默认就可以sudo)
su
apt-get install sudo
adduser your-login sudo
可以在虚拟机上做这个实验,进行简单的个人设置后,建一个快照(便于回滚),开始运行脚本。
顺便说一句,如果用虚拟机,最好用桥接(Bridge)模式,这样和主机(Host)在同一个网段。
10分钟:基本系统,全自动脚本
你可以一边阅读本章,一边运行本文最后的脚本。用自己的账号运行,脚本在需要sudo的时候,会问你密码。因为sudo会话默认超时是15分钟,所以最多要输入两次密码(注1)。
默认安装basic版,我花了大约7分钟。如果你用国内镜像,应该会更快。advanced版(主要是支持Markdown)多装了几个模块,那几个模块比较花时间,总共大约15分钟。
下面对脚本做一简单的说明。
先安装MySQL, Nginx, PHP。我用轻量级的nginx搭配php-fpm(没用apache搭配php)。为了适应各系统,尽量不指定版本号。Debian9上的MySQL已经默认使用MariaDB了,而且安装时不需要设置root密码了。这对自动安装是极好的,sudo mysql 就可以以root登录MySQL了。Debian8/Ubuntu17上则需要设置一个环境变量,才能达到同样的效果。
接下来,安装composer,PHP的包管理工具;drush,Drupal的命令行工具,让安装配置自动化的神器。
软件装好后,建一个空的数据库,给Drupal用。顺便把相应的账号密码写入自己的~/.my.cnf,便于无密码使用mysql命令行。
为了全自动,我们直接从nginx网站下载Drupal的配置。怎么从网页中抓取特定的内容,严谨的做法还是有点小麻烦的,我就简单粗暴,直接用perl -pe去除所有html tag,得到文本,然后grep -A定位和抓取配置文件内容,最后用perl和sed做一点修改。
最后用drush安装站点,composer安装需要的PHP模块,再用drush创建用户,安装/配置模块、主题。Drupal8还要求把域名加入到信任站点的列表里,否则会有警告。脚本同时也修改了这方面的配置:加入了一个域名,一个服务器的IP地址。
关于权限,养成好习惯,不要全程root:安装系统软件,修改系统配置用sudo;安装Drupal, PHP模块,用自己的账号;Drupal的modules, themes, sites/default 目录最后改为由Web server账号(www-data)所有,这样以后可以通过浏览器/网页安装/缷载Drupal模块/主题。sites/default如果不改为www-data所有,网页安装时会要使用FTP方式,那就麻烦点。
注1:每次运行composer命令(install或require)后,再运行sudo,会要求输入密码。这样,不管sudo会话的超时有多长,这个脚本至少会要两次sudo的密码。这是遗憾的地方。
网站管理员和普通用户的账号/密码都在脚本里;安装脚本成功结束后会提示网站入口地址。
先用管理员登录。下图是管理界面之一:系统状态。
下图是用户权限管理。顺便设置权限让注册用户可以创建/修改“文章”(Article)这一类型。顺便说一句:如果enable revision,网站立马就可以变成WiKi类型的站点。
20分钟:百家号,封面图
安装完成后就有了一个所见即所得的编辑器CKEditor,可以实现图文混排的编辑,和百家号的编辑界面相当。
百家号可以指定3张图作为封面,而公众号/简书是默认使用文中的第一张图。
为实现百家号的效果,增加一个字段,叫作"Cover”。这个字段可以设置为允许3个值,就是3张图,和百家号类似。
然后设置这个字段只在摘要页面(Teaser)显示,在默认页面中隐藏(Disabled),这样,这个封面图就会只显示在首页中,不会显示在正文中。这样就实现了百家号的效果。
30分钟:公众号,水印
公众号/订阅号可以自动给图片加水印,而百家号和简书没这个功能。
在Drupal8中,可以通过模块 Image effects 来实现水印的效果。
Drupal8用“样式”(Style)来处理/生成图片缓存。一种样式其实就是对原图的一种/一组处理,最常见的是缩放。Drupal8自带3种样式:大、中、小(缩略图)。
我们直接在自带的 Large 样式里加入水印这种处理。
水印可以设置:位置,大小,透明度等等。
这样,对上传的图片,显示的是自动缩小(至800x800以内)并带水印的图。另外,“水印”本身修改后,也不用重新处理/上传每一张图,因为原图在服务器上,可以重新合成。
40分钟:简书,Markdown
简书支持两种编辑格式,通常的所见即所得和Markdown。
Drupal里的“格式”也可以做到同样的事,一种格式(Text format)就是对文本的一组处理/转换。
新建一种格式,名字叫“Markdown”,其中包括 markdown,语法高亮、自动生成目录。
使用Markdown,就意味使用纯文本编辑器,所以不能用CKEditor上传图片了。于是我们回归原始的Image字段:
- 这个字段是多值的,所以可以上传任意多张图片;
- 这个字段不直接显示在文章中,要在显示中要设置为”Disabled”(图在“百家号”那一节);
- 这样,图片可以插入在文章的任何位置,和上载的顺序无关。
为了帮助在文章里插入图片的链接,使用了Insert模块。界面如下图所示:
不足和长处
不足:
- 不支持图片的剪贴板操作。百家号/公众号/简书支持直接粘贴剪贴板内的图片,自动上载。
- 不支持拖放。简书是可以支持拖放上载的(百家号看上去也有,但在Chrome里测试未成功)。
- 目前的选图/插入略感麻烦。简书的Markdown的同屏编辑/预览是极好的,在Drupal里用简单的模块组合做不出来。
总之,简书的编辑界面是我见过的最好的。
长处:
- 支持自动生成文章目录。在文章中插入 “[ toc ]” 就会变成目录。
- 支持响应式(Responsive )页面。随着窗口大小不同,设备不同,界面呈现为不同的布局。这个功能得益于Drupal的主题。Drupal8自带的主题 Bartik 与时俱进,其实已经不错了。当然,还有不少第三方主题都是响应式的。
- 有大量的第三方模块/主题。做一个快乐的伸手党,就能很容易地实现一些功能和效果。
响应式效果简介:
- 下图是在手机上显示的网站首页——自动变成了单列模式,并隐藏了菜单;
- 在PC上,则显示为如本文第1图的双列模式;如果窗口变窄,也会变为单列模式;
- 在iPad上,旋转屏幕,也可以看到这种效果的变化。
欢迎访问我的网站,直接体验。
下图是PC上和手机上的文章目录效果。对于长文章,有目录还是方便一些。
附:自动安装脚本
请用具有sudo权限的普通用户直接运行此脚本,不要以sudo方式运行,也不要用root账号运行。
脚本在以下系统测试通过:
- Debian 9.0(无GUI);
- Debian 8.8(有GUI);
- Ubuntu 17.04(有GUI)。
脚本可以多次运行。比如安装好后,再运行脚本,会清除掉数据库重装;但系统软件(如果没有升级版)不会再重装。
#!/bin/bash
#Setup a Drupal8 site from scratch, including MySQL, Nginx, PHP, Drupal
#Tested on clean Debian9/8, Ubuntu17
#Updated: 6/27/2017, LobLab
set -e
PROFILE=$1
if [ -z "$PROFILE" ]; then
PROFILE=basic
#PROFILE=advanced
fi
DB_NAME=drupal8
DB_USER=drupal8
DB_PASS=JlTpr9wGryiN
SITE_NAME=LobLab
SITE_FQDN=loblab.myvnc.com
SITE_URL=http://$SITE_FQDN
ADMIN_NAME=admin
ADMIN_PASS=P2fOA9b6ctG
ADMIN_MAIL=admin@loblab.com
USER_NAME=demo
USER_PASS=dH9BbntT1Mq
USER_MAIL=demo@loblab.com
DRUPAL_DIR=/var/www/drupal8
DRUSH="drush -r $DRUPAL_DIR -l $SITE_URL -y"
function log_msg() {
echo $(date +'%m/%d %H:%M:%S') - $*
}
function install_system_packages() {
log_msg "Install system packages..."
codename=$(lsb_release -cs)
export DEBIAN_FRONTEND=noninteractive
sudo -E apt-get -y install mysql-server
sudo apt-get -y install mysql-client
sudo apt-get -y install nginx
if [ "$codename" == "jessie" ]; then
sudo apt-get -y install php5-fpm php5-mysql php5-gd
else
sudo apt-get -y install php-fpm php-mysql php-gd php-xml php-mbstring
fi
log_msg "Install system packages... done."
}
function install_php_composer() {
log_msg "Install PHP composer..."
# See https://getcomposer.org/download/
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php -r "if (hash_file('SHA384', 'composer-setup.php') === '669656bab3166a7aff8a7506b8cb2d1c292f042046c5a994c43155c0be6190fa0355160742ab2e1c88d40d5be660b410') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
php composer-setup.php
php -r "unlink('composer-setup.php');"
# See https://getcomposer.org/doc/00-intro.md#globally
sudo mv composer.phar /usr/local/bin/composer
log_msg "Install PHP composer... done."
}
function setup_database() {
log_msg "Setup database..."
sudo mysql -e "CREATE DATABASE IF NOT EXISTS $DB_NAME;"
sudo mysql -e "GRANT ALL PRIVILEGES ON $DB_NAME.* TO '$DB_USER'@'localhost' IDENTIFIED BY '$DB_PASS' WITH GRANT OPTION;"
sudo mysql -e "FLUSH PRIVILEGES;"
echo "[client]" > ~/.my.cnf
echo "user=$DB_USER" >> ~/.my.cnf
echo "password=$DB_PASS" >> ~/.my.cnf
echo "socket=/var/run/mysqld/mysqld.sock" >> ~/.my.cnf
chmod 600 ~/.my.cnf
log_msg "Setup database... done."
}
function setup_nginx_drupal_config() {
log_msg "Donwload nginx config for drupal..."
cfgfile=/etc/nginx/sites-available/drupal8
wget -q -O - https://www.nginx.com/resources/wiki/start/topics/recipes/drupal/ |
perl -pe 's/<.+?>//g' |
grep "server {" -A 102 |
perl -mHTML::Entities -ne 'print HTML::Entities::decode_entities($_);' |
perl -pe "s/server_name .+?;/server_name _;/" |
sed '/location ~ \\..*\/.*\\.php$ {/i \ \ \ \ rewrite ^/core/authorize.php/core/authorize.php(.*)$ /core/authorize.php$1;' |
sudo tee $cfgfile
ps -A | grep php5 && php5=1 || php5=0
if [ $php5 -eq 1 ]; then
sudo perl -pe 's/#(fastcgi_pass.+php5.+fpm.sock;)/$1/' -i $cfgfile
sudo perl -pe 's/(fastcgi_pass.+php7.+fpm.sock;)/#$1/' -i $cfgfile
fi
cd /etc/nginx/sites-enabled
sudo ln -sf $cfgfile drupal8
sudo rm -f default
sudo service nginx restart
log_msg "Donwload nginx config for drupal... done."
}
function install_drush() {
log_msg "Install drush..."
php -r "readfile('http://files.drush.org/drush.phar');" > drush
chmod +x drush
sudo mv drush /usr/local/bin
drush -y init
log_msg "Install drush... done."
}
function install_drupal() {
log_msg "Install drupal..."
#https://www.drupal.org/documentation/install/developers
cd $(dirname $DRUPAL_DIR)
sudo chown -R $MY_ACCOUNT .
drush -y dl drupal --drupal-project-rename=$(basename $DRUPAL_DIR)
cd $DRUPAL_DIR
composer install
if [ "$PROFILE" == "advanced" ]; then
echo "Install PHP module: geshi/geshi..."
composer require geshi/geshi
echo "Install PHP module: michelf/php-markdown..."
composer require michelf/php-markdown
fi
drush -y site-install standard --db-url="mysql://$DB_USER:$DB_PASS@localhost/$DB_NAME" --site-name=$SITE_NAME --account-name="$ADMIN_NAME" --account-pass="$ADMIN_PASS" --account-mail="$ADMIN_MAIL"
host1=$(hostname -I | perl -pe 's/\./\\./g' | perl -pe 's/ //g')
host2=$(echo $SITE_FQDN | perl -pe 's/\./\\./g')
config="\$settings['trusted_host_patterns'] = array(
'^$host1$',
'^$host2$',
);
"
cfgfile=sites/default/settings.php
sudo chmod 644 $cfgfile
echo "$config" >> $cfgfile
sudo chmod 444 $cfgfile
sudo chown -R $WEB_ACCOUNT modules themes sites/default
log_msg "Install drupal... done."
}
function setup_drupal_users() {
log_msg "Create drupal users..."
drush user-create $USER_NAME --password="$USER_PASS" --mail="$USER_MAIL"
log_msg "Create drupal users... done."
}
function setup_drupal_modules() {
log_msg "Download & enable/disable drupal modules..."
sudo chown -R $MY_ACCOUNT modules
$DRUSH en smtp
$DRUSH en image_effects
$DRUSH en insert
$DRUSH en toc_api
$DRUSH en toc_filter
$DRUSH en captcha
$DRUSH en image_captcha
if [ "$PROFILE" == "advanced" ]; then
$DRUSH en geshifilter
$DRUSH en markdown
fi
sudo chown -R $WEB_ACCOUNT modules
log_msg "Download & enable/disable drupal modules... done."
}
function setup_drupal_themes() {
log_msg "Download & enable/disable drupal themes..."
sudo chown -R $MY_ACCOUNT themes
$DRUSH en adminimal_theme
sudo chown -R $WEB_ACCOUNT themes
$DRUSH config-set system.theme default bartik
$DRUSH config-set system.theme admin adminimal_theme
log_msg "Download & enable/disable drupal themes... done."
}
function main() {
install_system_packages
MY_ACCOUNT=$(id -un):$(id -gn)
WEB_ACCOUNT=$(ps -Ao user,group,cmd | grep nginx | grep worker | head -n 1 | awk '{printf "%s:%s\n", $1, $2}')
install_php_composer
install_drush
setup_database
setup_nginx_drupal_config
install_drupal
setup_drupal_users
setup_drupal_modules
setup_drupal_themes
$DRUSH cron
addr=$(hostname -I | sed 's/ //g')
log_msg "Succeeded. Please access http://$addr/"
}
main