Script d’ajout de blog

Pour aller plus loin de l’installation de notre serveur, on va écrire un script de création de blog qui nous facilitera la vie.

Je ne vous explique pas en détail ce que contient ce script qui à mon avis n’est pas terminé. Je vos conseil de reprendre juste la structure des actions à mener puis de le réécrire vous même, c’est un très bon exercice pour apprendre à écrire des script shell. Ce script permet juste avec quelques questions d’ouvrir un nouveau blog sur notre plateforme avec son administrateur, ses répertoires, son sous-domaines et son accès FTP, etc…Toutes les actions qu’il effectue sont prévues uniquement pour une installation strictement identique à celle de notre série d’article mais vous pouvez largement vous en inspirer et l’adapter sans trop de mal à votre serveur. C’est mon premier vrai script alors soyez indulgents.

Installation

Vous le trouverez en pièce jointe de cet article, il suffit de le rapatrier sur votre serveur et le rendre exécutable :

wget http://jcd.lv/public/VPSOVH/dcnewblog
mv dcnewblog /usr/local/bin/dcnewblog
chown root:root /usr/local/bin/dcnewblog
chmod 770 /usr/local/bin/dcnewblog

PS: Si vous l’exécutez sur votre serveur sans même avoir jeté un coup d’œil dans son code, vous ne méritez pas d’avoir un serveur !

Script

#!/bin/bash
#
# A shell script to create a new Dotclear’s blog
# with associated new user, domain, vhost, ftp…
#
# Copyright (c) Jean-Christian Denis <http://jcd.lv>
# This script is licensed under GNU GPL version 2.0 or above
#
# All the path, programs, IP, port etc present in this script
# are for our specific installation of our server.
#
# Get more detail about this script at:
# <http://jcd.lv/post/2013/04/10/Script-d-ajout-de-blog>
#
# And more detail about our server installation at:
# <http://jcd.lv/post/2013/04/01/Debian-squeeze-64-sur-VPS-OVH>
#
# TODO:
# – Pick up server domain from apache
# – Set user quota
#

PROGNAME=$(basename $0) # Program name
PROGVERSION=’2013.04.21.1′ # Program version

clear # Clean up the console and say hello
echo “Dotclear’s new blog creation script”

#
# Help and usage of this script
#

scriptusage=”
$PROGNAME help and usage:

** Exemples **
$PROGNAME -f -p /var/dotclear -l newuser -m newuser@.com -d exemple.com

** Arguments **
-p, \-dotclear-path Dotclear’s root directory -p /var/dotclear
-d, \-server-domain Blogs main domain -d exemple.com
-m, \-blog email Blog contact email -m my.real@.mail
-l, \-blog-login Blog identifiant -l MyFirstBlog
-f, \-fake-mode Do nothing (fake mode) -f
-h, \-help This help -h
-v, \-version Show program version -v

** Fake mode **
Execute script but do nothing on accounts and SQL and FTP.

** About Dotclear’s root directory **
This script uses Dotclear’s configuration file that
contains all we need to connect to the SQL server,
generate password, etc…

** About blog identifiant **
The blog identifiant is used in multiple places.
– the blog id, of course
– the blog name, can be changed later
– the blog administrator login
– the blog sub-domain name
– the FTP user account
– the system user account

** About author **
More detail about this script on:
<http://jcd.lv/?q=Script-d-ajout-de-blog>

Copyright (c) Jean-Christian Denis <http://jcd.lv>
This script is licensed under GNU GPL version 2.0 or above

#
# List of variables used in this script
#

fakemode= # Fake mode, do not execute actions
showend= # Memory for a cooool display

serverip= # This server IPv4
serverdomain= # Blogs main server domain name
ftpport= # FTP server listen port

dcpath= # Dotclear’s install path
dcfile= # Dotclear’s configuration file path
dcdbhost= # Dotclear’s database host
dcdbuser= # Dotclear’s database port
dcdbpassword= # Dotclear’s database password
dcdbname= # Dotclaer’s database name
dcdbprefix= # Dotclear’s database table prefix
dcmasterkey= # Dotclear’s master key
dcadminurl= # Dotclear’s administration URL

bloglogin= # Blog administrator login (and blog id…)
blogemail= # Blog administrator email
blogpassword= # Blog administration password
bloguid= # Blog unique identifiant
blogurl= # Blog public URL
blogdate= # Blog creation date

#
# Functions
#

# Error that stop script execution
# Take one argument: <message>
function error_exit
{
echo -e “${PROGNAME}: Abording script execution – ${1:-“Unknow error”}” 1>&2
exit 1
}

# Display a warning message
# Take one argument: <message>
function error_msg
{
showend=
echo -e “\e[30;31m/!\ \e[0m${1:-“Unknow warning”}”
return 0
}

# Display a query
# Take one argument: <message>
function query_msg
{
echo -e “\e[30;36m(?) \e[0m${1:-“What is your answer”}? ”
return 0
}

# Display a message if it is in fake mode
# Take one argument: <message>
function fake_msg
{
echo -e “\e[30;33m [ fake mode ]\e[0m ”
return 0
}

# Display one line of detail of variables
# Take 2 arguments: <name> <value>
function detail_msg
{
# Find lengh of argument
n=”$1″
l=$(echo ${#n})

# Split display with tab
if [ “$l” -lt 12 ]; then
t=” ”
elif [ “$l” -gt 19 ]; then
t=” ”
else
t=” ”
fi

# Display formated message
echo -e “\e[30;35m – \e[0m$1$t$2”
return 0
}

# Display a message that begin a script block
# Take one argument: <message>
function begin_block
{
showend=1
echo -e “\e[30;33m[+] \e[0m${1:-“Starting new action”}… ”
return 0
}

# Display a message that end a script block
# Take no arguments
function end_block
{
if [ -n “$showend” ]; then shwoend=; echo -e “\e[30;32m->- \e[0mDone”; fi
return 0
}

# Display the script help
# Take no arguments
function show_usage
{
echo -e “$scriptusage”
exit 0
}

# Display the script version
# Take no arguments
function show_version
{
echo -e “$PROGNAME $PROGVERSION”
exit 0
}

# Test commands and exit if not exist
# Take up to 9 arguments: <command name to check>
function command_exist
{
# Loop through arguments
for arg in $*
do
# ‘command -v’ returns 0 when argument not found
command -v $arg >/dev/null || error_exit “Missing command ‘$arg’.”
done
return 0
}

# Check if Dotlcear’s path exists
# Take one argument: <dcpath>
function check_dc_path
{
# Path is not empty and it is a directory
if [ -n “$1” -a -d “$1″ ]; then
dcpath=”$1”
check_dc_file “$1”
return 0
else
dcpath=
dcfile=
error_msg “Require a valid Dotclear’s path.”
return 1
fi
}

# Check if Dotclear’s configuation file exists
# Take one argument: <dcpath>
function check_dc_file
{
# File name
f=”$1″”/inc/config.php”
# File name is not empty and it is a file and it is readable
if [ -n “$f” -a -f “$f” -a -r “$f” ]; then
dcfile=”$f”
return 0
else
dcpath=
dcfile=
error_msg “Failed to read Dotclear’s configuration file.”
return 1
fi
}

# Check server domain
# Take one argument: <serverdomain>
function check_server_domain
{
# Domain contains letters and numbers and one dot near the end
if [[ “$1″ =~ ^[A-Za-z0-9]{2,}\.[A-Za-z]{2,4}$ ]]; then
serverdomain=”$1″
return 0
else
serverdomain=””
error_msg “Server domain is not valid.”
return 1
fi
}

# Check if identifiant is used on whole system
# Take one argument: <bloglogin>
function check_identifiant
{
# Check form of bloglogin
check_blog_login “$1”
[ $? -eq 1 ] && return 1

# Check system user
check_system_account “$1”
[ $? -eq 1 ] && return 1

# Check ftp account
check_ftp_account “$1”
[ $? -eq 1 ] && return 1

# This part was removed as dotclear user has not right on mysql table
# Check sql account
#check_sql_account “$1”
#[ $? -eq 1 ] && return 1

# Check Dotclear account
check_dotclear_account “$1”
[ $? -eq 1 ] && return 1

return 0
}

# Check blog login form
# Take one argument: <bloglogin>
function check_blog_login
{
# Login contains only 4 to 24 letters
if [[ “$1″ =~ ^[A-Za-z]{5,24}$ ]]; then
bloglogin=”$1”
return 0
else
bloglogin=
error_msg “Blog login is not valid.”
return 1
fi
}

# Check if blog login is a system user
# Take one argument: <bloglogin>
function check_system_account
{
rsp=$(n=$(egrep “^$1” /etc/passwd 2>/dev/null); echo $?)

if [ $rsp -eq 2 ]; then
bloglogin=
error_exit “Failed to read system user file”
return 1

elif [ $rsp -eq 0 ]; then
bloglogin=
error_msg “That blog login already exists (System)”
return 1

else
return 0
fi
}

# Check if blog login is a ftp account
# Take one argument: <bloglogin>
function check_ftp_account
{
rsp=$(n=$(egrep “^$1” /etc/vsftpd/passwd 2>/dev/null); echo $?)

if [ $rsp -eq 2 ]; then
bloglogin=
error_exit “Failed to read FTP user file”
return 1

elif [ $rsp -eq 0 ]; then
bloglogin=
error_msg “That blog login already exists (vsFTPd)”
return 1

else
return 0
fi
}

# Check if blog logi is a sql account
# Take one argument: <bloglogin>
function check_sql_account
{
q=”SELECT EXISTS(SELECT 1 FROM mysql.user WHERE user = ‘”$1″‘)”
rsp=$(mysql \-batch \-skip-column-names -h “$dcdbhost” -P “$dcdbport” -u “$dcdbuser” -p”$dcdbpassword” -e “$q” 2>/dev/null)

if [ $? -ne 0 ]; then
bloglogin=
error_exit “Failed to connect to MySQL server”
return 1

elif [ $rsp -eq 1 ]; then
bloglogin=
error_msg “That blog login already exists (MySQL)”
return 1

else
return 0
fi
}

# Check if blog login is a Dotcler account
# Take one argument: <bloglogin>
function check_dotclear_account
{
# Check Dotclear’s user
q=”SELECT EXISTS(SELECT 1 FROM “$dcdbprefix”user WHERE user_id = ‘”$1″‘)”
rsp=$(echo “$q” | mysql -s -h “$dcdbhost” -P “$dcdbport” -D “$dcdbname” -u “$dcdbuser” -p”$dcdbpassword” 2>/dev/null)

if [ $? -ne 0 ]; then
bloglogin=
error_exit “Failed to query MySQL server”
return 1

elif [ $rsp -eq 1 ]; then
bloglogin=
error_msg “That blog login already exists (Dotclear user)”
return 1
fi

# Check Dotclear’s blog
q=”SELECT EXISTS(SELECT 1 FROM “$dcdbprefix”blog WHERE blog_id = ‘”$1″‘)”
rsp=$(echo “$q” | mysql -s -h “$dcdbhost” -P “$dcdbport” -D “$dcdbname” -u “$dcdbuser” -p”$dcdbpassword” 2>/dev/null)

if [ $? -ne 0 ]; then
bloglogin=
error_exit “Failed to query MySQL server”
return 1
elif [ $rsp -eq 1 ]; then
bloglogin=
error_msg “That blog login already exists (Dotclear blog)”
return 1
fi

return 0
}

# Check blog email
# Take one argument: <blogemail>
function check_blog_email
{
if [[ “$1″ =~ .*@.* ]]; then
blogemail=”$1”
return 0
else
blogemail=
error_msg “A valid email is required to send blog password to its admnistrator.”
return 1
fi
}

# Find DB host and port from full host (work for IPv4 only)
# Take one argument: <dcdbhost>
function set_host_port
{
# Extract host part
dcdbhost=$(echo “$1” | cut -d’:’ -f1)
# Extract port part
dcdbport=$(echo “$1” | cut -d’:’ -f2)
# Clean up
[ “$1” = “$dcdbport” ] && dcdbport=0

return 0
}

# Display Dotclear’s configuration file constant
# Take one argument: <PHP Constant to find>
function get_dc_constant
{
# Read file as php file and echo searched constant
rsp=$(php -r “define(‘DC_RC_PATH’,true); include ‘”$dcpath”/inc/config.php’; echo “$1″;” 2>/dev/null)
[ $? -ne 0 ] && error_exit “Failed to parse Dotclear’s value of ‘$1’.”
echo “$rsp”
return 0
}

# Find and set FTP port
# This method follows our installation of vsftp
# Take no arguments
function set_ftp_port
{
# Is there a directive ‘listen_port=xxx’ in vsftpd configuration ?
p=$( grep listen_port /etc/vsftpd.conf | cut -d’=’ -f2 )
if [ -n “$p” ]; then
ftpport=”$p”
else
ftpport=’21’
fi

return 0
}

# Query SQL server (only command without response)
# Take one argument: <a sql query>
function execute_sql_query
{
rsp=$(mysql -h “$dcdbhost” -P “$dcdbport” -D “$dcdbname” -u “$dcdbuser” -p”$dcdbpassword” -e “$1” 2>/dev/null)
[ $? -ne 0 ] && error_exit “Failed to query MySQL server”
return 0
}

# Encrypt data. Reproduce has_hmac from PHP and also Cleabricks crypt::hmac
# Take at least 3 arguments: <digest> <data> <key>
function hash_hmac
{
digest=”$1″
data=”$2″
key=”$3″
shift 3
echo -n “$data” | openssl dgst “-$digest” -hmac “$key” “$@”
return 0
}

#
# Check list
#

# Script requires root privilege
[ “$UID” -ne 0 ] && error_exit “Require root privileges. Try ‘sudo $PROGNAME”

# Check required programs (and list all command used in this script)
command_exist ‘grep’ ‘egrep’ ‘cut’ ‘mkdir’ ‘chown’ ‘chmod’ ‘date’ ‘head’ ‘fold’
command_exist ‘awk’ ‘mysql’ ‘md5sum’ ‘openssl’ ‘apache2’ ‘php’ ‘htpasswd’ ‘vsftpd’

#
# Parse script arguments
#

# Inform user that he can use arguments
if [ $# = 0 ]; then
error_msg “No arguments given. Try ‘$PROGNAME \-help’ for more information.”
else
begin_block “Reading script arguments”
while [ “$1” != “” ]; do
case $1 in
-p | \-dotclear-path ) shift
detail_msg “Found ‘Dotclear path'” “$1”
check_dc_path “$1”
;;
-d | \-server-domain ) shift
detail_msg “Found ‘server domain'” “$1”
check_server_domain “$1”
;;
-m | \-blog-email ) shift
detail_msg “Found ‘blog email'” “$1”
check_blog_email “$1”
;;
-l | \-blog-login ) shift
detail_msg “Found ‘blog login'” “$1”
check_blog_login “$1”
;;
-f | \-fake-mode ) detail_msg “Found ‘fake mode'” “Enable”
fakemode=1
;;
-h | \-help ) detail_msg “Found ‘help'” “Enable”
show_usage
;;
-v | \-version ) detail_msg “Found ‘version'” “Enable”
show_version
;;
*) error_exit “Unknow operand. Try $PROGNAME \-help for more information.”
esac
shift
done
end_block
fi

#
# Parse Dotclear’s configuration file
#

# Dotclear’s configuration file is very important
# as it contains informations to connect to mysql server
# and to encode passwords.
if [ -z “$dcpath” ]; then
while true
read -p “`query_msg “What is the installation directory of Dotclear”`” dcpath
do
check_dc_path “$dcpath”
if [ -n “$dcpath” -a -n “$dcfile” ]; then break; fi
done
fi

begin_block “Reading configuration file ‘$dcfile'”

set_host_port $(get_dc_constant ‘DC_DBHOST’)
dcdbuser=$(get_dc_constant ‘DC_DBUSER’)
dcdbpassword=$(get_dc_constant ‘DC_DBPASSWORD’)
dcdbname=$(get_dc_constant ‘DC_DBNAME’)
dcdbprefix=$(get_dc_constant ‘DC_DBPREFIX’)
dcmasterkey=$(get_dc_constant ‘DC_MASTER_KEY’)
dcadminurl=$(get_dc_constant ‘DC_ADMIN_URL’)

end_block

#
# Guess required informations
#

# Check identifiant first to reset bloglogin if it exists
if [ -n “$bloglogin” ]; then check_identifiant “$bloglogin”; fi

# If some variables not set then guess information
if [ -z “$serverdomain” -o -z “$bloglogin” -o -z “$blogemail” ]
then
begin_block “Requiring more informations”

# Blogs main server domain
if [ -z “$serverdomain” ]; then
while true
read -p “`query_msg ‘What is the blogs main domain for this blog sub-domain’`” serverdomain
do
check_server_domain “$serverdomain”
[ -n “$serverdomain” ] && break
done
fi

# Blog id, it is also the login for blog admin, ftp and sql account
if [ -z “$bloglogin” ]
then
while true
read -p “`query_msg ‘What is the identifiant of the blog’`” bloglogin
do
check_blog_login “$bloglogin”
[ -n “$bloglogin” ] && check_identifiant “$bloglogin”
[ -n “$bloglogin” ] && break
done
fi

# Blog admin email (we just do a quick test on it)
if [ -z “$blogemail” ]
then
while true
read -p “`query_msg ‘What is the email of the administrator of the blog’`” blogemail
do
check_blog_email “$blogemail”
[ -n “$blogemail” ] && break
done
fi
end_block
fi

#
# Additionals variables
#

# Blogurl
blogurl=”$bloglogin.$serverdomain”

# Blog password real password from random func
# List of chars is taken from library clearbricks crypt::createPassword
blogpassword=`head -c 500 /dev/urandom | tr -dc ‘a-zA-Z0-9!@$’ | fold -w 8 | head -n 1`

# On OVH VPS server we can find our IP with these two methods
# serverip=$( grep “$(cat ‘/etc/hostname’)” /etc/hosts | cut -d’ ‘ -f1 | head -n 1 )
serverip=$( ifconfig venet0:0 | grep inet | cut -d: -f2 | cut -d’ ‘ -f1 )

# FTP port – following our installation of vsftpd
set_ftp_port

#
# Display all variables
#

begin_block “Showing configured variables”

detail_msg “Server Domain name” “$serverdomain”
detail_msg “Server IPv4” “$serverip”
detail_msg “Server FTP port” “$ftpport”
detail_msg “Database Host” “$dcdbhost”
detail_msg “Database Port” “$dcdbport”
detail_msg “Database User” “$dcdbuser”
detail_msg “Database Password” “$dcdbpassword”
detail_msg “Database Name” “$dcdbname”
detail_msg “Database Table prefix” “$dcdbprefix”
detail_msg “Dotclear Administration URL” “$dcadminurl”
detail_msg “Dotclear Master key” “$dcmasterkey”
detail_msg “Blog Login” “$bloglogin”
detail_msg “Blog Password” “$blogpassword”
detail_msg “Blog Email” “$blogemail”
detail_msg “Blog URL” “$blogurl”

end_block

# Continue or not ?
read -n 1 -s -p “`query_msg ‘Do you want to start creation of the new blog [y/n]’`” startcreate
echo “”
# Stop script if answer is not ‘y’
if [ ! “$startcreate” = “y” ]; then
begin_block “Stopping script, bye”
# We can add features later here
end_block
exit 0
fi

#
# Create system user
#

begin_block “Creating system account for user ‘$bloglogin'”
if [ -n “$fakemode” ]; then fake_msg;
else
# Encode password for system user
systempassword=$(perl -e ‘print crypt($ARGV[0], “password”)’ $blogpassword)

# Add user to the system
useradd -d “/home/$bloglogin” -s /bin/bash -m “$bloglogin” -p ‘”$systempassword”‘
fi
end_block

#
# Create folders and blog files
#

begin_block “Creating files structure in ‘/home/$bloglogin'”
if [ -n “$fakemode” ]; then fake_msg;
else
# Make path recursively
mkdir -p “/home/$bloglogin/www/public”
# Set them the property of the new user
chown -R “$bloglogin”:”$bloglogin” “/home/$bloglogin/www”
# Set there permissions
chmod -R 755 “/home/$bloglogin/www”
fi
end_block

#
# Create FTP account
#

begin_block “Creating FTP account for user ‘$bloglogin'”
if [ -n “$fakemode” ]; then fake_msg;
else
# Encode FTP password and add it to the FTP user list
htpasswd -b /etc/vsftpd/passwd “$bloglogin” “$blogpassword”

# Restart FTP service to take account of this change
/etc/init.d/vsftpd restart
fi
end_block

#
# Create virtual host
#

begin_block “Creating blog virual host ‘$blogurl'”
if [ -n “$fakemode” ]; then fake_msg;
else
# Set up virtual host file
echo “<VirtualHost *:80>
ServerAdmin $blogemail
ServerName $blogurl
ServerAlias www.$blogurl
DocumentRoot /home/$bloglogin/www
<Directory /home/$bloglogin/www>
Options Indexes FollowSymLinks MultiViews
AllowOverride All
Order allow,deny
allow from all
</Directory>
</VirtualHost>” > “/etc/apache2/sites-available/$bloglogin”

# Enable vhost in Apache
a2ensite “$bloglogin”

# Restart Apache to take account of this change
/etc/init.d/apache2 restart
fi
end_block

#
# Create blog specifics files
#

begin_block “Creating blog files ‘$bloglogin'”
if [ -n “$fakemode” ]; then fake_msg;
else
# Set up index file
echo “<?php define(‘DC_BLOG_ID’,’$bloglogin’);
require ‘$dcpath/inc/public/prepend.php’;
?>” > “/home/$bloglogin/www/index.php”

# Set up Apache rewrite rules
echo ‘RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) index.php?$1’ > “/home/$bloglogin/www/.htaccess”

fi
end_block

#
# Create blog in database
#

begin_block “Creating blog ‘$bloglogin’ in database”
if [ -n “$fakemode” ]; then fake_msg;
else
# Prepare some date and time
scriptuxts=$(date +%s)
scriptdate=$(date +”%Y-%m-%d”)
scripttime=$(date +”%H:%M:%S”)

# Encode blog password
dcpassword=$( hash_hmac ‘sha1’ ‘”$blogpassword”‘ ‘”$dcmasterkey”‘ )

# Blog uid from blogid and time
bloguid=`echo -n “$blogid$scriptuxts” | md5sum | awk ‘{print $1}’`

# Insert dotclear’s blog
execute_sql_query ”
INSERT INTO “$dcdbprefix”blog
(blog_id, blog_uid, blog_creadt, blog_upddt, blog_url, blog_name, blog_desc, blog_status)
VALUES
(‘”$bloglogin”‘, ‘”$bloguid”‘, ‘”$scriptdate” “$scripttime”‘, ‘”$scriptdate” “$scripttime”‘, ‘http://”$blogurl”‘, ‘”$bloglogin”‘, ”, 0)
;”

# Insert dotclear’s user
execute_sql_query ”
INSERT INTO “$dcdbprefix”blog
(user_id, user_pwd, user_email, user_default_blog, user_creadt, user_upddt)
VALUES
(‘”$bloglogin”‘,'”$dcpassword”‘,'”$bloglogin”‘,'”$scriptdate” “$scripttime”‘, ‘”$scriptdate” “$scripttime”)
;”

# Insert dotclear’s permissions
execute_sql_query ”
INSERT INTO “$dcdbprefix”blog
(user_id, blog_id, permissions)
VALUES
(‘”$bloglogin”‘, ‘”$bloglogin”‘, ‘|admin|’)
;”
fi
end_block

#
# Send email
#

begin_block “Sendind email to ‘$blogemail’ with account informations”
if [ -n “$fakemode” ]; then fake_msg;
else

mail -s ‘Your blog is installed !’ “$blogemail”<<ENDOFFILE
Hello,
Your new blog is installed and ready to use.

Blog:
\—
You can manage your blog from your browser.

Blog public URL: $blogurl
Administration URL: $dcadminurl
Login: $bloglogin
Password: $blogpassword

FTP:
\-\-
You can access your public directory by FTP.

IP: $serverip
Port: $ftpport
Login: $bloglogin
Password: $blogpassword

Have fun!
ENDOFFILE
fi
end_block

#
# End of script
#

echo “New Dotclear’s blog and related accounts successfully created!”
exit 0

Au suivant

Dans le prochain article nous allons prendre soin de notre serveur.

Atbildēt

Jūsu e-pasta adrese netiks publicēta. Obligātie lauki ir atzīmēti kā *