텍스트 큐브 판올림

1.6판 역시 발표된 직후 문제가 발견되서 간단한 패치가 있었다. 나는 텍스트 큐브 판올림을 자주 하는 편이 아니다. 그 이유는 텍스트 큐브를 상당히 많이 패치해서 사용하고 있고 그 중 가장 많은 패치를 해야 하는 것이 바로 절대 주소 패치였기 때문이다. 그러나 텍스트 큐브 1.5.1판 부터 절대 주소 패치가 이루어졌기 때문에 별다른 고민 없이 1.5.3판에서 1.6판으로 판올림했다.

텍스트 큐브 판올림

얼마 전 텍스트 큐브가 1.6으로 판올림했다. 베타판, RC판이 숨 가쁘게 올라왔고 의 공식 홈페이지에서 사용하고 있는 스킨이 예뻐서 1.6판이 발표되기를 내심 기다렸다. 그러나 1.6판이 올라 왔지만 바로 판올림하지 않았다. 그 이유는 정식판이 발표된 직후 패치나 소수 판올림이 잦았기 때문이다.

1.6판 역시 발표된 직후 문제가 발견되서 간단한 패치가 있었다. 나는 텍스트 큐브의 판올림은 자주 하는 편이 아니다. 그 이유는 텍스트 큐브를 상당히 많이 패치해서 사용하고 있고 그 중 가장 많은 패치를 해야 하는 것이 바로 절대 주소 패치였기 때문이다. 그러나 텍스트 큐브 1.5.1판 부터 절대 주소 패치가 이루어졌기 때문에 별다른 고민 없이 1.5.3판에서 1.6판으로 판올림했다.

.htaccess 파일 문제

보통은 판올림을 하기 전에 DB도 백업하고 파일도 백업한 뒤 판올림을 한다. 패치한 내용이 많아 만약의 사태에 대비해야 하기 때문이다. 그러나 텍스트 큐브로 판올림 한 뒤로는 패치할 것이 많지 않아 DB만 백업하고 파일은 덮어쓰는 편이다. 다만 1.6에서는 Rewrite 기능이 바뀌었기 때문에 .htaccess 파일의 변경이 있을 것으로 생각했다.

배포판에는 .htaccess 파일이 포함되어 있지 않아 파일을 백업하지 않고 그대로 판올림을 했다. 그리고 나서 기존의 .htaccess 파일이 삭제되고 .htaccess 파일이 새로 생성되었다는 것을 알았다. 파일을 백업하지 않아 기존의 스패머 정보와 개인적으로 설정한 부분이 모두 날라가 버렸다. 참조 URL 스팸TraceWatch때문에 상당히 많은 내용을 추가해 두었는데...

처음에는 새로 .htaccess 파일을 만들면서 기존의 파일은 최소한 백업되었을 것으로 생각했지만 의외로 어디에도 백업 파일이나 백업 정보는 남아 있지 않았다. 이 문제는 텍스트 큐브 개발진이 꼭 고려해 주었으면 하는 아쉬움으로 남는 부분이었다.

도메인 주소를 최신 글 주소로 전환

나는 블로그주소문자로 사용하고 '쪽당 글의 수도 1로 설정'해서 사용한다. 아울러 https://offree.net/처럼 도메인 주소로 접속하면 자동으로 최근 글로 이동하도록 텍스트 큐브를 패치해서 사용하고 있다. 이렇게 하는 이유는 간단하다. 이 방법을 사용하면 블로그의 모든 주소가 실제 주소로 표시되기 때문이다.

한 예로 쪽 탐색 막대에 커서를 올려 두면 주소는 보통 https://offree.net/?page=3처럼 실제 주소가 아니라 쪽 번호로 표시된다. 그러나 패치해서 사용하면 쪽 탐색 막대에 표시되는 주소도 https://offree.net/entry/Benchmark-USB-Memory-Memorette-Memorive-Ucell 처럼 글의 실제 주소가 표시된다. 하나의 글에 하나의 주소를 갖는 것검색 엔진 최적화(SEO: Search Engine Optimization)에 더 도움이 되기 때문이다. 또 주소문자로 하는 이유는 문자 주소가 다른 형태의 주소 보다 검색 엔진에 더 잘 검색되기 때문*이기도 하다.

구글에서 검색해 보면 알 수 있지만 실제 글을 늦게 올려도 내 글이 항상 구글 검색 상위에 나타나는 이유도 비슷한 맥락이다. 아울러 제목을 영문 주소로 하면 애드센스의 매치율도 더 올라간다. 즉 애드센스를 달고 있는 사람이라면 수익의 증가도 기대할 수 있기 때문에 이 방법을 사용한다.

그러나 텍스트 큐브 1.6에서 Rewrite 방법을 바꾸면서 도메인 주소를 실제 최근 글 주소로 전환하는 패치는 이제 사용할 수 없다. 그 이유는 예전에는 파일과 아파치Rewrite 모듈을 이용해서 /로 접근하면 자동으로 /blog/index.php 파일로 접근하도록 했었는데 1.6 판부터는 도메인 전환 기법을 아파치 Rewrtie 모듈 기반에 rewrite.php 기반으로 바꾸었기 때문이다.

RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^(.+[^/])$ $1/ [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ rewrite.php [L,QSA]

//마지막 행에서 알 수 있듯이 모든 요청은 `rewrite.php`로 전환된다.

따라서 텍스트 큐브 1.6으로 판올림 한 뒤 이전 패치처럼 도메인 주소로 접속하면 자동으로 최근 글의 실제 주소로 전환하려면 다음 방법을 사용하면 된다.

  1. 좋아하는 편집기(예: Editplus)로 interface/index.php 파일을 연다.
  2. 변경전의 내용을 변경뒤의 내용으로 바꾼다. 바뀐 부분은 빨간색으로 표시했다.

    변경전
    fireEvent('OBStart');
    if(empty($suri['id'])) {  // Without id.
    $skin = new Skin($skinSetting['skin']);
    if(empty($suri['value']) && $suri["directive"] == "/" 
        && count($coverpageMappings) > 0 
        && getBlogSetting("coverpageInitView") 
        && isset($skin->cover)) {
        require ROOT . '/lib/piece/blog/begin.php';
        dress('article_rep', '', $view);
        dress('paging', '', $view);
        require ROOT . '/lib/piece/blog/cover.php';
    } else {
        list($entries, $paging) = getEntriesWithPaging($blogid, $suri['page'],
            $blog['entriesOnPage']);
        require ROOT . '/lib/piece/blog/begin.php';
        require ROOT . '/lib/piece/blog/entries.php';
    }
    
    require ROOT . '/lib/piece/blog/end.php';
    } else {  // With id.
    list($entries, $paging) = getEntryWithPaging($blogid, $suri['id']);
    if (isset($_POST['partial'])) { // Partial output.
        header('Content-Type: text/plain; charset=utf-8');
        $skin = new Skin($skinSetting['skin']);
        $view = '[##_article_rep_##]';
        require ROOT . '/lib/piece/blog/entries.php';
        $view = removeAllTags($view);
        if ($view != '[##_article_rep_##]')
            print $view;
    } else {
        require ROOT . '/lib/piece/blog/begin.php';
        if (empty($entries)) {
            header('HTTP/1.1 404 Not Found');
            if (empty($skin->pageError)) { 
                dress('article_rep', '<div style="text-align:center;
                font-size:14px;font-weight:bold;padding-top:50px;
                margin:50px 0;color:#333;background:url(' . $service['path'] . 
                '/image/warning.gif) no-repeat top center;
                ">' . _text('존재하지 않는 페이지입니다.') . '</div>', $view);
            } else{
                dress('article_rep', NULL, $view); 
                dress('page_error', $skin->pageError, $view);
            }
            unset($paging);
        } else {
            require ROOT . '/lib/piece/blog/entries.php';
        }
        require ROOT . '/lib/piece/blog/end.php';
    }
    }
    fireEvent('OBEnd');
    
    변경뒤
    if(empty($suri['id'])) {  // Without id.
    /*$skin = new Skin($skinSetting['skin']);
    if(empty($suri['value']) && $suri["directive"] == "/" && count($coverpageMappings) >   0 
        && getBlogSetting("coverpageInitView") 
        && isset($skin->cover)) {
        require ROOT . '/lib/piece/blog/begin.php';
        dress('article_rep', '', $view);
        dress('paging', '', $view);
        require ROOT . '/lib/piece/blog/cover.php';
    } else {
        list($entries, $paging) = getEntriesWithPaging($blogid, $suri['page'], 
            $blog['entriesOnPage']);
        require ROOT . '/lib/piece/blog/begin.php';
        require ROOT . '/lib/piece/blog/entries.php';
    }
    
    require ROOT . '/lib/piece/blog/end.php';*/
    
    // 추가된 부분 시작
    list($entries, $paging) = getEntriesWithPaging($blogid,
        $suri['page'], $blog['entriesOnPage']);
    if(ereg('MSIE 6',$_SERVER['HTTP_USER_AGENT'])) 
        $slogan=iconv('UTF-8', 'EUC-KR', $entries[0]['slogan']);
    else $slogan=$entries[0]['slogan'];
    header("Location:".불blogURL."/entry/".불slogan);
    // 추가된 부분 끝
    
    } else {  // With id.
    // if문 바깥쪽에 있어도 되지만 만약을 위해 if 문 안쪽으로 이동
    fireEvent('OBStart');
    
    list($entries, $paging) = getEntryWithPaging($blogid, $suri['id']);
    if (isset($_POST['partial'])) { // Partial output.
        header('Content-Type: text/plain; charset=utf-8');
        $skin = new Skin($skinSetting['skin']);
        $view = '[##_article_rep_##]';
        require ROOT . '/lib/piece/blog/entries.php';
        $view = removeAllTags($view);
        if ($view != '[##_article_rep_##]')
            print $view;
    } else {
        require ROOT . '/lib/piece/blog/begin.php';
        if (empty($entries)) {
            header('HTTP/1.1 404 Not Found');
            if (empty($skin->pageError)) { 
                dress('article_rep', '<div style="text-align:center;
                font-size:14px;font-weight:bold;padding-top:50px;margin:50px 0;
                color:#333;background:url(' . $service['path'] .
                '/image/warning.gif) no-repeat top center;
                ">' . _text('존재하지 않는 페이지입니다.') . 
                '</div>', $view);
            } else{
                dress('article_rep', NULL, $view); 
                dress('page_error', $skin->pageError, $view);
            }
            unset($paging);
        } else {
            require ROOT . '/lib/piece/blog/entries.php';
        }
        require ROOT . '/lib/piece/blog/end.php';
    }
    
    // if문 바깥쪽에 있어도 되지만 만약을 위해 if 문 안쪽으로 이동
    fireEvent('OBEnd');
    }
    

통계 데이타 패치

텍스트 큐브에는 '키워드 통계'라는 기능이 있다. 참조 URL을 분석해서 어떤 단어를 이용해서 블로그에 접속했는지 통계를 보여주는 기능이다. 그런데 키워드 통계는 다른 사람에 비해 키워드 수도 많고 키워드당 개수도 다른 사람에 비해 월등히 많다. 그 이유는 간단하다. 텍스트 큐브에서는 키워드 통계를 낼 때 최근 1500개의 데이타만 가지고 키워드 통계를 내지만 나는 5000개의 데이타로 키워드 통계를 내도록 패치했기 때문이다.

알약은 그렇다고 처도 키워드 순위 5위 이내에 'bluenlive'님과 '2bwithu'님이 들어있다. bluenlive님을 내 블로그에서 찾는 이유는 BluenLive님 약올리기라는 글 때문이지만 2bwithu님까지 내 블로그에서 찾는 이유를 모르겠다. 'bluenlive'님은 BluenLive님 약올리기라는 글 때문에 유입이 늘었다고 좋아했지만 내가 뺏아온 셈이다. 그 이유는 BluenLive님 약올리기라는 글로 'bluenlive'님 블로그를 방문하는 사람은 점점 줄지만 검색을 통해 찾아오는 사람은 점점 늘 가능성이 많기 때문이다. ㅋㅋㅋ

나처럼 키워드 통계 데이타의 개수를 바꿀 사람은 다음 방법을 사용하면된다.

  1. 좋아하는 편집기로 components/Textcube.Model.Statistics.php 파일을 불러온다.
  2. function getRefererLogs()를 찾은 뒤 SQL 문의 LIMIT문을 다음처럼 바꾼다. 바뀐 부부은 빨간색으로 표시했다.

    변경전
    return POD::queryAll("
    SELECT host, url, referred 
    FROM {$database['prefix']}RefererLogs 
    WHERE blogid = $blogid 
    ORDER BY referred DESC 
    LIMIT 1200
    ");
    
    변경뒤
    return POD::queryAll("
    SELECT host, url, referred 
    FROM {$database['prefix']}RefererLogs 
    WHERE blogid = $blogid 
    ORDER BY referred DESC 
    LIMIT 5000
    ");
    

LIMIT의 값이 커질 수록 더 많은 데이타로 통계를 내기때문에 검색어 인기 순위를 더 정확하게 알 수 있다. 그러나 LIMIT의 값이 커질 수록 속도는 더 느려진다. 다만 방문자에게는 아무런 영향을 끼치지 않으며 관리 도구의 키워드 통계 페이지를 출력하는 속도가 느려진다.

위지윅 편집기

텍스트 큐브의 위지윅 편집기는 입력한 데이타를 임으로 변경한다. HTML 모드와 위지윅 모드를 서로 전환해 보면 쉽게 알 수 있다. 이러한 문제가 싫어서 나는 HTML 모드에서 위지윅 모드로 전환해도 데이타를 바꿀 수 없도록 패치해서 사용하며, 편집기의 기본 모드로 위지윅이 아니라 HTML로 설정해서 사용하고 있다.

태그 리스트 플러그인

내 블로그가 다른 사람의 블로그 보다 검색이 더 잘되는 이유는 또 있다. 블로그 소스 보기를 한 뒤 META 태그를 확인해 보면 Keywords 항목에 태그로 사용한 내용이 올라와 있는 것을 알 수 있다. 시절에 발표된 플러그인 중 태그 리스트라는 플러그인이 있었는데 이 플러그인을 사용하면 태그를 META 태그 Keywords로 변환해 준다. 검색 엔진 최적화(SEO)를 해본 사람은 알겠지만 META 태그의 Keywords에 페이지의 성격을 나타내는 키워드를 등록해 두면 검색 엔진의 가중치가 올라간다. 따라서 Keywords가 없는 태그 보다 더 잘 그러고 더 명확하게 검색된다.

그러나 이 플러그인은 텍스트 큐브에서는 동작하지 않는다. 따라서 이 플러그인 역시 텍스트 큐브에 동작할 수 있도록 패치했다. 방법은 다음과 같다.

  1. 좋아하는 편집기로 plugins/TagList/index.php 파일을 불러온다.
  2. 변경전 코드를 변경뒤 코드로 바꾼다. 바뀐 부분은 빨간색으로 표시했다.

    변경전
    $tmp = array();
    foreach ($entries as $entry) {
        $tags = getTags($entry["id"]);
        foreach ($tags as $tag) {
            if (array_search($tag["name"], $tmp) === false)
                array_push($tmp, $tag["name"]);
        }
    }
    
    변경뒤
    // $blogid 추가
    $blogid = getBlogId();
    $tmp = array();
    foreach ($entries as $entry) {
        $tags = getTags($blogid, $entry["id"]);
        foreach ($tags as $tag) {
            if (array_search($tag["name"], $tmp) === false)
                array_push($tmp, $tag["name"]);
        }
    }
    

언어 설정

텍스트 큐브는 다국어를 지원한다. 아울러 이 언어 파일을 이용하면 텍스트 큐브에 출력되는 메시지를 원하는 메시지로 바꿀 수 있다. 내가 항상 바꾸는 메시지는 관리자에게만 보여지는 "비공개로 변경합니다"와 "공개로 변경합니다"이다. 이 부분을 "비공개"와 "공개"로 바꾸어 사용한다. 이렇게 하는 이유는 제목 옆에 글의 분류와 관리 기능이 표시되도록 하고 사용하고 있다. 그런데 "비공개로 변경합니다"를 사용하면 관리 기능이 너무 길어져서 줄바꿈되는 때가 많기 때문이다.

따라서 텍스트 큐브가 출력하는 메시지를 바꾸고 싶다면 다음 방법에 따라 원하는 메시지로 바꾸면 된다.

  • 좋아하는 편집기로 languages/ko.php 파일을 불러온다.
  • 편집기의 찾기 기능을 이용해서 바꿀 문자열(예: '비공개로 변경합니다')를 찾는다.
  • $__text 앞의 주석(//)을 제거하고 '작은 따옴표' 사이에 원하는 메시지를 입력한다.

    변경전
    //$__text['비공개로 변경합니다'] = '';
    
    변경뒤
    $__text['비공개로 변경합니다'] = '비공개';
    

팀블로그 설정

텍스트 큐브 1.6으로 판올림 한 뒤 이상한 현상이 생겼다. 로그인을 하고 댓글을 달아도 꼭 익명으로 표시되는 것이었다. 물론 링크도 생기지 않고 블로그 아이콘도 가져오지 못한다. 처음에는 버그일까 싶었다.

그러나 그 뒤 바로 팀블로그인 경우 각자의 블로그 주소를 설정할 수 있도록 바꾸어 달라고 inureyes님께 요청했다는 것을 떠올렸다. 이 것이 기억나 팀블로그 설정을 확인해 보니 다음처럼 팀블로그를 운영하는 경우 팀원이 자신의 블로그를 설정할 수 있는 기능이 새롭게 추가되어 있었다. 팀블로그인 경우 팀원이 자신의 블로그를 설정하는 방법은 다음과 같다.

  1. '관리도구/환경설정/계정정보'를 클릭한다.
  2. '대표 주소'를 '기본값'에서 '참여중인 블로그'나 '외부 주소'로 바꾼다. 블로그 주인은 '참여중인 블로그'로 바꾸면 되고 팀블로그에 참여하고 있는 팀원이라면 '외부 주소'를 선택하고 팀원의 블로그 주소를 입력하면 된다.

  3. '변경하기' 단추를 클릭한다.

관리 메뉴

관리 메뉴를 보니 조금 이상한 현상이 발생했다. 바로 '피', '텍'처럼 한글자 메뉴가 생긴 것이다. 조금 이상하다는 생각이 들어 전체 화면 보기를 하자 '피는 피드 통계', '텍은 텍스트 큐브'라는 메뉴였다. 일부러 화면 폭이 좁으면 자동으로 줄어 들도록 한 기능인지 아니면 다른 이유가 있는 것인지 모르겠다. 그러나 이처럼 메뉴가 한글자로 줄어 버리기 때문에 사용하기는 조금 불편했다. 의도적으로 추가한 기능이라면 한글자가 아니라 최소한 두글자 정도는 보여야 메뉴를 구분하기 쉬울 것 같았다.

남은 이야기

Needlworks의 다른 분들도 열심히 하시지만 특히 inureyes님은 텍스트 큐브 개발에 온 정성을 다 쏟고 있다. 대학원에 텍스트 큐브 개발에 스킨 디자인까지 내가 보기에 거의 눈코뜰새 없는 것 같다. 따라서 포항에 가게 되면 꼭 한턱 쏠 예정이다. 다만 시간이 맞지 않아서 언제가 될지는 미지수이다.

'inureyes'라는 별명을 기억하기 상당히 힘들었다. 그런데 'inureyes'님에 따르면 이 별명도 DOS의 8.3 제한의 잔재라고 한다. 'In your eyes'를 줄인 것이라고 한다. 의미를 모르면 기억하기 어렵지만 의미를 알고난 뒤에는 기억하기 상당히 쉬웠다. 물론 DoA가 더 쉽다. ㅋㅋㅋ

현재 내 블로그는 '소핑몰 전문가'인 mepay님과 팀블로그로 운영하고 있다. 물론 장기적으로 blogda.net이라는 도메인을 이용한 전문 팀블로그를 따로 만들 생각이다. 그러나 이렇게 팀블로그를 하다 보니 한 가지 문제가 생겼다. 'mepay'님이 내 블로그에 로그인한 뒤 글을 쓰면 팀블로그임에도 불구하고 mepay님의 블로그 역시 https://offree.net/으로 잡힌다는 점이다. 따라서 이 문제에 대한 수정을 'inureyes'님께 부탁을 드렸고 텍스트 큐트 1.6에는 이런 요청이 반영되었다.

관련 글타래