[PHP] 영카트5 DB 테이블별로 덤프하기

영카트5의 DB 데이터를 테이블별로 덤프하기 위한 코드이다. 코드 테스트는 PHP 7.0.x 버전, MariaDB 10.1.x 버전에서 완료했다.

<?php
require_once './_common.php';

$tables  = [];
$exclude = [
    'g5_autosave'
    'g5_visit',
    'g5_visit_sum'
];

$result = sql_query("SHOW TABLES");

for ($i = 0; $row = sql_fetch_array($result); $i++) {
    $tables[] = array_pop($row);
}

$userInfo = posix_getpwuid(fileowner(__FILE__));
$owner = $userInfo['name'];

$dir = '/home/dbbackup/'.$owner.'/'.date('Ymdhi');
mkdir($dir, 0755, true);

// 7일 초과 경과된 data 삭제
$basedir = dirname($dir);
$basetime = time() - 86400 * 7;

foreach (scandir($basedir) as $val) {
    if (in_array($val, array('.', '..')))
        continue;

    $d = $basedir.'/'.$val;

    if (filemtime($d) < $basetime) {
        if (is_dir($d)) {
            foreach (scandir($d) as $v) {
                if (in_array($v, array('.', '..')))
                    continue;

                if (is_file($d.'/'.$v))
                    @unlink($d.'/'.$v);
            }

            rmdir($d);
        } else {
            @unlink($d);
        }
    }
}

// DB 백업
$host = G5_MYSQL_HOST;
$user = G5_MYSQL_USER;
$pass = G5_MYSQL_PASSWORD;
$database = G5_MYSQL_DB;

foreach ($tables as $table) {
    if (in_array($table, $exclude))
        continue;

    $file = $dir.'/'.$table.'.sql';

    exec("mysqldump --user={$user} --password={$pass} --host={$host} {$database} {$table} --result-file={$file} 2>&1", $output);
}

$exclude 에 덤프 때 제외할 테이블을 지정할 수 있다.

우분투 서버 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=en_US.UTF-8 LANGUAGE="en_US:en"
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/www ;

    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
while [[ $dbpassword == '' ]]
do
    read -s -p "Enter DB Root Password: " dbpassword
    echo -e ""
done

while ! mysql -u root -p$dbpassword  -e ";" ; do
     read -s -p "Can't connect, Enter DB Root Password: " dbpassword
     echo -e ""
done
mysql -uroot -p${dbpassword} -e "CREATE DATABASE ${username} DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_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 를 각각 매치시켜줄 때 사용할 수 있다.