[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 를 각각 매치시켜줄 때 사용할 수 있다.

카카오 번역 API 사용을 위한 PHP 클라이언트

카카오 번역 API 사용을 위한 PHP 클라이언트 코드이다. PHP 7.0 이상의 환경에서 사용할 수 있다.

카카오 번역 API : https://developers.kakao.com/docs/restapi/translation

<?php
/**
* @author chicpro <chicpro@gmail.com>
* @copyright (c) chicpro
* @link https://ncube.net
*/

namespace chicpro\KAKAO;

class TRANSLATE
{
    protected $host;
    protected $appKey;

    protected $query;
    protected $sourceLanguage;
    protected $targetLanguage;

    public function __construct(string $appKey = '')
    {
        $this->host   = 'https://kapi.kakao.com/v1/translation/translate';
        $this->appKey = $appKey;
    }

    public function setHost(string $host)
    {
        $this->host = $host;
    }

    public function setAppKey(string $appKey)
    {
        $this->appKey = $appKey;
    }

    public function setQuery(string $query)
    {
        $this->query = $query;
    }

    public function setSourceLanguage(string $source)
    {
        $this->sourceLanguage = $source;
    }

    public function setTargetLanguage(string $target)
    {
        $this->targetLanguage = $target;
    }

    public function sendRequest()
    {
        $headers = array(
            'Authorization: KakaoAK ' . $this->appKey
        );

        $postData = [
            'src_lang'    => $this->sourceLanguage,
            'target_lang' => $this->targetLanguage,
            'query'       => $this->query
        ];

        $ch = curl_init();

        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ch, CURLOPT_URL, $this->host);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));

        $json = curl_exec($ch);

        if ($errno = curl_errno($ch)) {
            $result = new \stdClass;
            $result->errno = $errno;
            $result->error = 'Curl error: ' . curl_error($ch);
        } else {
            $response = json_decode($json);
            $result = $response;
        }

        return $result;
    }
}

카카오 번역 API 예제 코드는 아래와 같다. Read More

[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 이다.

[PHP] 방문로그에 특정 에이전트 제외하고 로그 남기기

PHP 에서 특정 사용자 에이전트(예: Googlebot 등)를 제외하고 방문로그를 DB에 남기는 코드이다. 방문로그 테이블 구조에 따라 아래 코드는 수정된 후 사용되어야 한다.

<?php
$_AGENT_EXCLUDE = array(
    'mod_pagespeed',
    'bot'
);

if (!isset($_SESSION['ss_visit_log']) || !$_SESSION['ss_visit_log']) {
    if (str_replace($_AGENT_EXCLUDE, '', $_SERVER['HTTP_USER_AGENT']) == $_SERVER['HTTP_USER_AGENT']) {
        $sql = " insert into `{$nt['visit_table']}` ( vi_date, vi_time, vi_referer, vi_agent, vi_ip ) values ( :vi_date, :vi_time, :vi_referer, :vi_agent, :vi_ip ) ";
        $DB->prepare($sql);
        $DB->bindValueArray([
            ':vi_date'    => NT_TIME_YMD,
            ':vi_time'    => NT_TIME_HIS,
            ':vi_referer' => $_SERVER['HTTP_REFERER'] ? $_SERVER['HTTP_REFERER'] : '',
            ':vi_agent'   => $_SERVER['HTTP_USER_AGENT'],
            ':vi_ip'      => $_SERVER['REMOTE_ADDR']
        ]);

        $_SESSION['ss_visit_log'] = $DB->execute();
    }
}
$_AGENT_EXCLUDE 지정된 문자열을 HTTP_USER_AGENT 에 포함하고 있으면 로그를 DB에 남기지 않는다. 제외될 문자열은 배열인데 str_replace 함수를 이용해 치환 후 치환된 문자열과 원래 문자열이 비교해서 같은 경우에만 로그를 남기는 것이다. 코드의 8 라인에 해당된다.

[PHP] Slack Webhook Class

Slack Webhook 사용을 위한 PHP Class 코드이다.

<?php
/*
https://api.slack.com/incoming-webhooks
https://www.webpagefx.com/tools/emoji-cheat-sheet/
*/

class SLACK
{
    private $webHookUrl;
    private $channel;
    private $userName;
    private $message;
    private $iconEmoji;
    private $iconUrl;
    private $attachments;
    private $attachmentsText;
    private $attachmentsTitle;
    private $attachmentsPreText;
    private $attachmentsColor;
    private $attachmentsAuthor;
    private $attachmentsFields;
    private $attachmentsFooter;

    public function __construct($webHookUrl='', $userName='') {
        $this->webHookUrl        = $webHookUrl;
        $this->userName          = $userName;
        $this->iconEmoji         = '';
        $this->iconUrl           = '';
        $this->message           = '';
        $this->attachments       = array();
        $this->attachmentsFields = array();
    }

    public function setWebHookUrl($webHookUrl) {
        $this->webHookUrl = $webHookUrl;
    }

    public function setChannel($channel) {
        $this->channel = $channel;
    }

    public function setUserName($userName) {
        $this->userName = $userName;
    }

    public function setMessage($message) {
        $this->message = $message;
    }

    private function subString($str, $len=0, $suffix='…') {
        $_str = trim($str);

        if($len > 0) {
            $arrStr = preg_split("//u", $_str, -1, PREG_SPLIT_NO_EMPTY);
            $strLen = count($arrStr);

            if ($strLen >= $len) {
                $sliceStr = array_slice($arrStr, 0, $len);
                $str = join('', $sliceStr);

                $_str = $str . ($strLen > $len ? $suffix : '');
            } else {
                $_str = join('', $arrStr);
            }
        }

        return $_str;
    }

    public function setAttachmentsText($text, $len=0) {
        $this->attachmentsText = $this->subString($text, $len);
    }

    public function setAttachmentsTitle($title) {
        $this->attachmentsTitle = $title;
    }

    public function setAttachmentPreText($pretext) {
        $this->attachmentsPreText = $pretext;
    }

    public function setAttachmentsColor($color) {
        $this->attachmentsColor = $color;
    }

    public function setAttachmentsAuthor($author) {
        $this->attachmentsAuthor = $author;
    }

    public function setAttachmentsFields($title, $value, $short = false)
    {
        $this->attachmentsFields[] = array(
            'title' => $title,
            'value' => $value,
            'short' => $short
        );
    }

    public function setAttachmentsFooter($footer) {
        $this->attachmentsFooter = $footer;
    }

    private function setAttachments() {
        $this->attachments[] = array(
            'pretext'     => $this->attachmentsPreText,
            'title'       => $this->attachmentsTitle,
            'author_name' => $this->attachmentsAuthor,
            'text'        => $this->attachmentsText,
            'color'       => $this->attachmentsColor,
            'fields'      => $this->attachmentsFields,
            'footer'      => $this->attachmentsFooter,
            'mrkdwn_in'   => array('text', 'pretext')
        );
    }

    public function setIconEmoji($iconEmoji) {
        $iconEmoji = strip_tags(trim($iconEmoji));

        if($iconEmoji)
            $this->iconEmoji = $iconEmoji;
    }

    public function setIconUrl($iconUrl) {
        $iconUrl = strip_tags(trim($iconUrl));

        if($iconUrl)
            $this->iconUrl = $iconUrl;
    }

    public function send() {
        if($this->webHookUrl) {
            $this->setAttachments();

            $postData = array(
                'channel'     => $this->channel,
                'username'    => $this->userName,
                'icon_emoji'  => $this->iconEmoji,
                'icon_url'    => $this->iconUrl,
                'text'        => $this->message,
                'attachments' => $this->attachments,
                'mrkdwn'      => true,
                'link_names'  => 1
            );

            $ch = curl_init($this->webHookUrl);
            curl_setopt($ch, CURLOPT_CUSTOMREQUEST,  'POST');
            curl_setopt($ch, CURLOPT_POSTFIELDS,     'payload='.json_encode($postData));
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            $result = curl_exec($ch);
            curl_close($ch);

            return $result;
        } else {
            return 'WebHook URL Error';
        }
    }
}

기존 코드에서 fields 등 몇 가지 메세지 포맷을 추가했다.