우분투 서버 nginx, php 7.2.x, mariadb 10.3.x 설치 스크립트

우분투 서버에 nginx 최신 안정버전, php 7.2.x, mariadb 10.3.x 버전 설치를 위한 스크립트이다. 아래 스크립트트를 server.sh 등으로 저장한 후 실행 권한을 준 후 실행한다. 사용자명, 비밀번호, 도메인을 입력받아 설치를 진행하며 DB 생성을 위해 DB root 비밀번호 입력이 필요하다. 스크립트는 우분투 서버 16.04 LTS(64비트)에서 테스트 했다.

#!/bin/bash
# ================================================================== #
# nginx, php 7.2.x, mariadb 10.3.x install shell script for Ubuntu
# ================================================================== #
# Copyright (c) 2018 Seongho Jang https://ncube.net
# This script is licensed under MIT
# ================================================================== #

# Input username, password, domain
while [[ $username == '' ]]
do
    read -p "Enter Username: " username
done

while [[ $password == '' ]]
do
    read -s -p "Enter Password: " password
    echo -e ""
done

while [[ $domain == '' ]]
do
    read -p "Enter domain: " domain
done

# Update package
sudo apt-get update
sudo apt-get -y upgrade

# Set locale
#sudo dpkg-reconfigure locales
sudo apt-get -y install language-pack-ko-base language-pack-ko
sudo locale-gen ko_KR.UTF-8
sudo locale-gen en_US.UTF-8
sudo localectl set-locale LANG=ko_KR.UTF-8 LANGUAGE="ko_KR:ko"
sudo source /etc/default/locale

# Install mail
sudo apt-get -y install sendmail
sudo apt-get -y install mailutils

# Create user
sudo groupadd "$username"
sudo useradd -g "$username" -s /bin/bash -m "$username"
echo -e "$password\n$password\n" | sudo passwd "$username"

# Make directory
sudo mkdir -p /home/"$username"/www
sudo chown "$username"."$username" /home/"$username"/www

# Set timezone
sudo timedatectl set-timezone Asia/Seoul
sudo apt-get install -y rdate
sudo /usr/bin/rdate -s time.bora.net; /sbin/hwclock --systohc

# Install MariaDB 10.3.x
sudo apt-get install software-properties-common
sudo apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 0xF1656F24C74CD1D8
sudo add-apt-repository 'deb [arch=amd64,arm64,i386,ppc64el] http://ftp.kaist.ac.kr/mariadb/repo/10.3/ubuntu '$(lsb_release -cs)' main'
sudo apt-get update
sudo apt-get -y install mariadb-server

# Install nginx latest stable version
sudo sh -c "echo 'deb http://nginx.org/packages/ubuntu/ `lsb_release -cs` nginx' >> /etc/apt/sources.list"
sudo sh -c "echo 'deb-src http://nginx.org/packages/ubuntu/ `lsb_release -cs` nginx' >> /etc/apt/sources.list"
curl http://nginx.org/keys/nginx_signing.key | apt-key add -
sudo apt-get update
sudo apt-get install -y nginx

# Install PHP 7.2.x
sudo apt-get -y install python-software-properties
sudo add-apt-repository ppa:ondrej/php
sudo apt-get update
sudo apt-get install -y php7.2-cli php7.2-fpm php7.2-bcmath php7.2-bz2 php7.2-common php7.2-curl php7.2-dba php7.2-gd php7.2-json php7.2-mbstring php7.2-mysql php7.2-opcache php7.2-readline php7.2-soap php7.2-xml php7.2-xmlrpc php7.2-zip

# nginx configure
sudo service nginx stop

sudo cat > /etc/nginx/conf.d/"$domain".conf <<WEBCONF
server {
    listen 80 default_server ;
    server_name $domain www.$domain ;
    root /home/$username/pg ;

    access_log /var/log/nginx/$domain.access.log ;
    error_log  /var/log/nginx/$domain.error.log warn ;

    location / {
        index index.php index.html index.htm ;
    }
    
    include /etc/nginx/php.conf ;
    
}
WEBCONF

# Create database
sudo service mysql restart
read -s -p "Enter DB Root Password: " dbpassword
mysql -uroot -p${dbpassword} -e "CREATE DATABASE ${username} DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;"
mysql -uroot -p${dbpassword} -e "CREATE USER ${username}@localhost IDENTIFIED BY '${password}';"
mysql -uroot -p${dbpassword} -e "GRANT ALL PRIVILEGES ON ${username}.* TO '${username}'@'localhost';"
mysql -uroot -p${dbpassword} -e "FLUSH PRIVILEGES;"

# Daemon start
echo -e ""
sudo nginx -t
sudo php-fpm7.2 -t
sudo service php7.2-fpm restart
sudo service nginx restart

echo "Complete!"

/etc/nginx/php.conf 파일의 내용은 아래와 같다.

# Block dot file (.htaccess .htpasswd .svn .git .env and so on.)
location ~ /\. {
    deny all;
}

# Block (log file, binary, certificate, shell script, sql dump file) access.
location ~* \.(log|binary|pem|enc|crt|conf|cnf|sql|sh|key)$ {
    deny all;
}

# Block access
location ~* (composer\.json|contributing\.md|license\.txt|readme\.rst|readme\.md|readme\.txt|copyright|artisan|gulpfile\.js|package\.json|phpunit\.xml)$ {
    deny all;
}

location = /favicon.ico {
    log_not_found off;
    access_log off;
}

location = /robots.txt {
    log_not_found off;
    access_log off;
}

# Block .php file inside upload folder. uploads(wp), files(drupal), data(gnuboard).
location ~* /(?:uploads|default/files|data)/.*\.php$ {
    deny all;
}


location ~ [^/]\.php(/|$) {
    fastcgi_split_path_info ^(.+?\.php)(/.*)$;
    if (!-f $document_root$fastcgi_script_name) {
        return 404;
    }

    # flush
    fastcgi_keep_conn on;
    gzip off;
    proxy_buffering off;
    include fastcgi_params;
    fastcgi_param  SCRIPT_FILENAME    $document_root$fastcgi_script_name;
    fastcgi_read_timeout 3600;
    fastcgi_pass unix:/run/php/php7.2-fpm.sock;
    fastcgi_index index.php;       
}

PhpSpreadsheet 를 이용한 엑셀파일 다운로드 개발

PHPExcel을 사용해서 엑셀 파일을 생성해왔는데 PHPExcel의 개발이 중단되어 PhpSpreadsheet를 사용하게 됐다.

Githut Repo : https://github.com/PHPOffice/PhpSpreadsheet
개발문서 : https://phpspreadsheet.readthedocs.io/en/develop/

PhpSpreadsheet 패키지 설치는 Composer를 이용하며 사용에 필요한 PHP 버전 등은 아래와 같다.

  • PHP version 5.6 or newer
  • PHP extension php_zip enabled
  • PHP extension php_xml enabled
  • PHP extension php_gd2 enabled (if not compiled in)

Composer 를 이용한 PhpSpreadsheet 설치는 아래의 명령을 실행한다.

composer require phpoffice/phpspreadsheet

Compser를 이용해 PhpSpreadsheet 를 설치했다면 아래의 코드로 엑셀파일 다운로드 기능을 테스트 해볼 수 있다. Read More

워드프레스 포스트 편집 화면에 메타박스 추가하기

위 이미지와 같은 커스텀 메타박스를 편집 화면에 추가하는 방법으로 플러그인 형태로 코드를 작성했다.

<?php

/**
 * @package Codepub Meta box
 * @version 1.0
 */
/*
Plugin Name: Codepub Meta box
Plugin URI: https://ncube.net/
Description: This plugin add custom meta box.
Author: chicpro
Version: 1.0
Author URI: https://ncube.net/
*/

// meta box render
function codepub_meta_box($post)
{
    wp_nonce_field( basename( __FILE__ ), 'codepub_meta_box_nonce' );

    $codepub_meta_box_value = (int)get_post_meta($post->ID, 'codepub_meta_box_value', true);

    echo '<div>'.PHP_EOL;
    echo '<p>'.PHP_EOL;
    echo '<input type="checkbox" name="codepub_meta_box_value" id="codepub_meta_box_value" value="1"'.($codepub_meta_box_value ? ' checked="checked"' : '').'>'.PHP_EOL;
    echo '<label for="codepub_meta_box_value">메타박스</label>'.PHP_EOL;
    echo '</p>'.PHP_EOL;
    echo '</div>'.PHP_EOL;
}

function add_codepub_meta_box()
{
    foreach (array('post', 'page') as $post_type)
        add_meta_box( 'codepub_meta_box', __( 'Codepub 메타박스', 'codepub_meta_box' ), 'codepub_meta_box', $post_type, 'side', 'low' );
}

// Save meta value
function save_codepub_meta_box_data($post_id)
{
    if ( !isset( $_POST['codepub_meta_box_nonce'] ) || !wp_verify_nonce( $_POST['codepub_meta_box_nonce'], basename( __FILE__ ) ) ) {
        return;
    }

    // return if autosave
    if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
        return;
    }

    // Check the user's permissions.
    if ( ! current_user_can( 'edit_post', $post_id ) ) {
        return;
    }

    if ( isset( $_REQUEST['codepub_meta_box_value'] ) ) {
        update_post_meta( $post_id, 'codepub_meta_box_value', sanitize_text_field( $_POST['codepub_meta_box_value'] ) );
    } else {
        // delete data
        delete_post_meta( $post_id, 'codepub_meta_box_value' );
    }
}

add_action( 'admin_init', 'add_codepub_meta_box' );
add_action( 'save_post',  'save_codepub_meta_box_data' );

33 라인의 array('post', 'page') 에서 워드프레스 포스트 타입이 postpage인 경우에만 메타박스가 출력된다. 메타박스 디자인 부분과 데이터를 저장하는 부분이 포함되어 있다.

[PHP] 문자열에 포함된 다수의 특정 문자를 순차적으로 치환하기

문자열에 포함된 동일한 다수의 특정 문자를 순차적으로 치환하는 방법이다. 순차적으로 치환한다는 것의 의미가 불분명할 수 있는데.. 예를 들면 이런 것이다. a b a c d 문자열에서 a 를  a_1 b a_2 c d 로 치환하는 것이다. 설명을 자세히 할 능력이 없기 때문에 코드를 보자.

<?php
$string = 'test [form] string with [form] replace';

$form = '[ id : id_{{idx}} ]';

function replaceForm($form) {
    static $idx = 0;

    $idx++;

    return str_replace('{{idx}}', $idx, $form);
}

echo preg_replace_callback('#\[form\]#',
        function($match) use ($form) {
            return replaceForm($form);
        },
        $string);

위 코드는 문자열에 포함된 [form] 문자를 [ id : id_1 ] 과 같은 형식으로 치환하여 출력한다. 결과는 아래와 같다.

test [ id : id_1 ] string with [ id : id_2 ] replace

참고 : http://www.php.net/manual/en/function.preg-replace-callback.php

위의 예제를 수정하여 동일한 웹페이지에 다수의 [form] 문자열을 입력폼으로 치환하여 출력할 때 입력 필드의 id와 label의 for 를 각각 매치시켜줄 때 사용할 수 있다.

[PHP] 영카트5에 사용할 수 있는 사이트맵 생성 코드

영카트5에 등록된 상품의 사이트맵을 생성하는 PHP 코드이다. 사이트맵 생성 Class 는 https://github.com/o/sitemap-php/blob/master/Sitemap.php 를 이용한다. 사이트맵 xml 파일은 sitemap 디렉토리에 저장되며 웹서버의 파일 쓰기 권한이 부여되어야 한다.

<?php
if (PHP_SAPI != 'cli')
    die('');

require_once './_common.php';
require_once G5_LIB_PATH.'/Sitemap.php';

session_write_close();

if (isset($argv[1]) && $argv[1])
    define('SITE_URL', set_http($argv[1]));

if (!defined('SITE_URL') || SITE_URL == '')
    die('Please specify your site url.');

$sitemap = new Sitemap(SITE_URL);

$path = G5_PATH.'/sitemap/';

if (!is_writable($path))
    die('You do not have write permission.');

$sitemap->setPath($path);

// index
$sitemap->addItem('/');

// item
$sql = " select it_id, it_update_time from `{$g5['g5_shop_item_table']}` where it_use = '1' and it_soldout = '0' ";
$result = sql_query($sql);

for ($i = 0; $row = sql_fetch_array($result); $i++) {
    if (!$row['it_id'])
        continue;

    $sitemap->addItem('/shop/item.php?it_id='.$row['it_id'], '1.0', 'daily', substr($row['it_update_time'], 0, 10));
}

// sitemap create
$sitemap->createSitemapIndex(SITE_URL.'/sitemap/', 'Today');

위 코드를 실행하는 쉘스크립트 코드는 아래와 같다.

#!/bin/sh
DIRECTORY=$(cd `dirname $0` && pwd)

cd "${DIRECTORY}"

sudo -u www-data  php sitemap.php "$1"

위 쉘스크립트 실행은 아래와 같이 한다.

$ ./sitemap.sh example.com

쉘 상에서는 G5_URL 등의 상수가 제대로 정의되지 않기 때문에 사용할 수 있어 sh 파일 실행 때 도메인을 지정하는 방법으로 구현했다. 예제 코드와 Class 파일은 첨부된 압축파일에 포함되어 있다.

sitemap.tar.gz

crotntab 에 등록할 때는 아래와 같이 하면 된다.

# sitemap
1 5 * * * /home/example/www/sitemap.sh example.com

사이트맵 url 은 http://example.com/sitemap/sitemap-index.xml 이다.