반응형
블로그 이미지
개발자로서 현장에서 일하면서 새로 접하는 기술들이나 알게된 정보 등을 정리하기 위한 블로그입니다. 운 좋게 미국에서 큰 회사들의 프로젝트에서 컬설턴트로 일하고 있어서 새로운 기술들을 접할 기회가 많이 있습니다. 미국의 IT 프로젝트에서 사용되는 툴들에 대해 많은 분들과 정보를 공유하고 싶습니다.
솔웅

최근에 받은 트랙백

글 보관함


지난번 글에서는 pdf2text($filename) 함수에 있는 for 문 중간 까지 했습니다.

그 중간에 getObjectOptions() 함수를 call 하는 부분 바로 전까지 했는데요.


그 전까지는 PDF 안의 내용을 일단 바이너리 파일로 받아서 obj,endobj 구문별로 나는 다음에 다시 그 안의 내용을 stream,endstream 구문별로 나눴습니다.


그 stream 별로 나눈 값을 for 문 안에서 계속 getObjectOptions() 함수로 던져서 어떤 일을 하도록 시키는데.. 오늘은 그 어떤일이 어떤일인지 공부할 것 같습니다.


PDF 안의 내용을 가져오는 함수는 file_get_contents() 함수였고 그 바이너리 파일들을 다시 세분화 시킬 때 사용했던 함수가 PCRE 함수인 preg_match_all() 과 preg_match() 였었습니다.


그리고 추가로 PHP 정규 표현식 (regular expressions)과 PDF 구조에 대해서 알아야 했구요.


이제 getObjectOptions() 함수에 대해 알아보겠습니다.


function getObjectOptions($object) {
    $options = array();
    if (preg_match("#<<(.*)>>#ismU", $object, $options)) {
        $options = explode("/", $options[1]);
        @array_shift($options);

        $o = array();
        for ($j = 0; $j < @count($options); $j++) {
            $options[$j] = preg_replace("#\s+#", " ", trim($options[$j]));
           
            if (strpos($options[$j], " ") !== false) {
                $parts = explode(" ", $options[$j]);
                $o[$parts[0]] = $parts[1];
            } else
                $o[$options[$j]] = true;
        }
        $options = $o;
        unset($o);
    }

    return $options;
}


여기서도 PCRE 함수가 쓰이네요.

바이너리 파일 내용을 처리하기 위해서 이 함수들은 필수로 이해하고 있어야 할 것 같습니다.


우선 처음에 $options 라는 배열을 만들고 pdf2text() 함수 내에서 던져준 PDF 내의 각 stream 을 가지고 다룹니다.


preg_match("#<<(.*)>>#ismU", $object, $options)


받은 stream 블럭인 $object 안의 내용을 정규표현식인 #<<(.*)>>#ismU 로 구분해서 아까 만든 배열변수인 $options 에 담습니다.

정규표현식 #<<(.*)>>#ismU 가 뭔지 정확히 알면 좋겠는데...

혹시 정규표현식에 강하신 분 계시면 댓글에 이게 정확히 무엇을 말하는지 알려 주시면 감사하겠습니다.





그 다음은 explode() 함수를 썼습니다. 이 함수는 문자열을 특정 기준으로 자르는 함수입니다.

예제를 하나 보면요.


<?php
$str 
'one|two|three|four';

// positive limit
print_r(explode('|'$str2));

// negative limit (since PHP 5.1)
print_r(explode('|'$str, -1));
?>


이 소스를 돌리면 그 결과값은 아래와 같습니다.

Array
(
    [0] => one
    [1] => two|three|four
)
Array
(
    [0] => one
    [1] => two
    [2] => three
)


첫번째 파라미터는 구분자이고 두번째 파라미터는 작업할 문자열 그리고 마지막 파라미터는 limit 이라고 하는데요. 이 세번째는 옵션입니다.

위의 소스를 보면 2를 넣으면 두개로 구분해서 첫번째 | 를 기준으로 구분하고 나머지는 모두 한개의 값으로 처리하는군요.

두번째 소스는 마이너스 값을 넣었는데 | 구분자 이전의 값을 나누는 것 같습니다.

비슷한 함수로는 정규식을 사용해서 구분하는 preg_split() 이 있구요 반대되는 함수로는 implode() 함수가 있습니다.


지금 배우는 소스에서는 $options = explode("/", $options[1]); 로 구분자 / 을 기준으로 options 를 모두 나눴습니다.

여기서 / 는 뭐를 나타내는 것일까요?


지난번 글에 Hello World! 를 표시한 PDF 의 바이너리 파일을 보면 << , >> 구문 안에 어떤 정보들이 들어있고 그 안에 각각의 정보들이 / 나눠져 있는 걸 볼 수 있습니다.

/ 이 무슨 의미인지 알려면 PDF 구조에 대해 공부해야 할 것 같습니다.


obj, stream,<<,>>,/ 대충 지금까지 나온 PDF 내부에서 사용되는 기호입니다. 


하여간 / 로 나는 값을 PHP 의 array_shift() 함수로 돌립니다.

배열의 첫번쨰 요소를 없애버리는 겁니다. 그리고 두번째 요소가 첫번째 요소로 되는거죠.


<?php
$stack 
= array("orange""banana""apple""raspberry");
$fruit array_shift($stack);
print_r($stack);
?>


이렇게 하면 결과가 아래와 같이 됩니다.

Array
(
    [0] => banana
    [1] => apple
    [2] => raspberry
)


Hello World! PDF 의 바이너리를 보면 / 다음엔 Size, Root 이런 문자가 오는데 이걸 없애 버리는 건가요?


하여간 그 다음으로 넘어가면 $o라는 배열 변수를 만듭니다.

그래서 방금전에 explode 까지 한 결과값인 $options 배열을 for 문으로 돌립니다.



$options 배열의 각각의 요소를 다시 preg_replace() 함수를 이용해서 변환을 시켜주네요.


preg_replace("#\s+#", " ", trim($options[$j]));


#\s+# 로 변환을 하고 그 결과값의 좌우 공백을 없앤 값을 $options 배열에 다시 넣어줍니다.


그리고 $options[$j] 안에 공백이 있으면 다시 그 공백을 기준으로 나눠서 $parts 변수에 담습니다.

그 다음에 방금 전 만들어 주었던 $o 의 $parts[0] 에 $parts[1] 을 담습니다.

만약 공백이 없다면 $o[$options[$j]] 에 true 값을 대입시킵니다.


그래서 이 $o  변수를 $options 에 담은 다음에 그 값을 return 합니다.


여기까지가 getObjectOptions() 메소드가 하는 일 입니다.


정리하면 #<<(.*)>>#ismU 으로 나누고 그걸 다시 / 으로 나누고 배열을 shift 한 다음에 배열안의 내용을 #\s+# 로 나눠서 공백이 있으면 공백을 기준으로 다시 나누고 공백이 없으면 $o[$options[$j]] 를 true 로 해서 이 $o의 값을 $options 에 담아서 return 을 해 줍니다.


정규표현식이 정확히 무엇을 하라는 것인지 알고 싶네요.

혹시 아시는 분 설명 부탁드려요.


오늘은 여기까지 할거구요.


위의 만들어진 $options 값을 pdf2text() 메소드에서 받아서 어떻게 처리하는지 다음에 알아 볼께요.


반응형

Comment


그럼 이전 글에 이어서 계속 진행하겠습니다.


pdf2text($filename) 을 하다가 마쳤었는데요.


이어서 알아볼 것은 preg_match_all 함수입니다.


preg_match_all("#obj(.*)endobj#ismU", $infile, $objects);


이런 초반부터 어려운게 걸렸네요.

이 함수에는 3개의 파라미터가 들어가는데요.

첫번쨰 파라미터는 정규표현식이 들어갑니다.

이 첫번째 파라미터의 패턴을 가지고 두번쨰 파라미터에 있는 객체내를 search 하는 겁니다.

그래서 그 정규식대로 구분해서 세번째 파라미터에 있는 변수에 결과를 담는거죠.


이 정규식과 관련해서는 여기여기 에 있는 글들을 참조하세요.

그리고 PHP 튜토리얼 사이트는 여기여기 가 있습니다.


이 preg_match_all 메소드에 대한 튜토리얼은 여기에 있습니다.


예제를 하나 보시면...


<?php
preg_match_all
("|<[^>]+>(.*)</[^>]+>|U",
    
"<b>example: </b><div align=left>this is a test</div>",
    
$outPREG_PATTERN_ORDER);
echo 
$out[0][0] . ", " $out[0][1] . "\n";
echo 
$out[1][0] . ", " $out[1][1] . "\n";
?>


위 코드를 실행하면 아래와 같은 결과를 얻습니다.


<b>example: </b>, <div align=left>this is a test</div> example: , this is a test


그러니까 첫번째 파라미터로 들어간 정규식은 모든 태그를 없애는 거나보네요.


그래서 결과가 배열 변수  $out 에 들어가게 되는데요. 

이 배열의 첫번째 열에는 full pattern 이 들어가고 두번쨰 열이 바로 이 태그가 없어진 값들이 들어갑니다.


정규식을 잘 몰라서 왜 그런지는 모르겠구요.


하여간 우리가 공부하는 소스코드는 PDF 의 내용을 담은 변수를 #obj(.*)endobj#ismU 라는 정규식을 써서 Search하고 그 값이 $objects 에 들어갑니다.


참고로 pdf 파일은 수많은 obj/endobj, stream/endstream , Startxref/Xref,Trailer 등으로 구성 돼 있습니다.



위와 같은 PDF 파일이 있다면 바이너리 파일은 아래와 같습니다.


%PDF-1.7

1 0 obj  % entry point
<<
  /Type /Catalog
  /Pages 2 0 R
>>
endobj

2 0 obj
<<
  /Type /Pages
  /MediaBox [ 0 0 200 200 ]
  /Count 1
  /Kids [ 3 0 R ]
>>
endobj

3 0 obj
<<
  /Type /Page
  /Parent 2 0 R
  /Resources <<
    /Font <<
      /F1 4 0 R 
    >>
  >>
  /Contents 5 0 R
>>
endobj

4 0 obj
<<
  /Type /Font
  /Subtype /Type1
  /BaseFont /Times-Roman
>>
endobj

5 0 obj  % page content
<<
  /Length 44
>>
stream
BT
70 50 TD
/F1 12 Tf
(Hello, world!) Tj
ET
endstream
endobj

xref
0 6
0000000000 65535 f 
0000000010 00000 n 
0000000079 00000 n 
0000000173 00000 n 
0000000301 00000 n 
0000000380 00000 n 
trailer
<<
  /Size 6
  /Root 1 0 R
>>
startxref
492
%%EOF


자세한 내용을 알고 싶으시면 여기 를 참조하세요.


이 프로그램 하나 이해하기 위해 공부해야 할 것들이 무지 많군요.






원래 소스로 돌아가서요.


    for ($i = 0; $i < count($objects); $i++) {
        $currentObject = $objects[$i];
        if (preg_match("#stream(.*)endstream#ismU", $currentObject, $stream)) {
            $stream = ltrim($stream[1]);
            $options = getObjectOptions($currentObject);
            if (!(empty($options["Length1"]) && empty($options["Type"]) && empty($options["Subtype"])))
                continue;

            $data = getDecodedStream($stream, $options);
            if (strlen($data)) {
                if (preg_match_all("#BT(.*)ET#ismU", $data, $textContainers)) {
                    $textContainers = @$textContainers[1];
                    getDirtyTexts($texts, $textContainers);
                } else
                    getCharTransformations($transformations, $data);
            }
        }
    }


아까 얻었던 $objects 배열의 count 만큼 for 문을 돌립니다.

바이너리 파일을 하나하나 텍스트 문자로 변환시키기 위해 전체 $objects 를 for 문 돌리는 거겠죠.

이 for 문 안에서는 $objects 배열에 있는 각각의 객체들을 일단 $currentObject 에 담네요.

그 다음에 다시 PCRE 함수가 나왔네요.

이와 관련해서는 저 위에 튜토리얼 페이지 링크를 걸어놨죠?  


if 문안에 preg_match("#stream(.*)endstream#ismU", $currentObject, $stream) 이 있습니다.


위 정규식으로 search 한 내용을 $stream 에 담슴니다.

한개의 stream 을 담는거네요.


PDF 소개글을 보면 Stream 은 아래와 같이 정의 돼 있습니다.

Stream (<< /Length ... >> stream ... endstream): embedded data, can be compressed. It starts with a dictionary that describes the stream such as its length or the encoding (/Filter) is uses.


stream 에 대해 자세히 공부하시려면 여기 로 가세요.


그 다음은 php2text.php 에 있는 getObjectOptions($currentObject)를 콜 합니다.


흠.... 소스를 자세히 뜯어 보니까 그 흐름은 좀 더 이해하게 되는데요...


이 소스를 완벽하게 이해하고 또 마음대로 수정해서 사용하려면

PHP 정규 표현식 (regular expressions) 를 알아야 하고 PCRE 함수를 알아야 하고 PDF 의 구조를 알아야 하네요.


일단 오늘의 성과는 이 소스를 이해하기 위해 필요한 지식 중 내가 뭐가 부족한지 알았습니다.


시간이 되면 파고 들겠는데... 그럴 시간이 있을 지 모르겠네요.


일단 오늘은 여기까지 하구요. 다음 글에서는 getObjectOptions() 메소드를 공부할 생각입니다.


그럼...


반응형

Comment


오늘은 PDF 파일에 있는 내용을 가져와서 브라우저에 텍스트로 뿌려 주는 것을 공부해 보겠습니다.

저희가 만든 웹앱에 식당 메뉴를 제공하려고 하는데요.
식당을 운영하는 회사에서 메뉴를 PDF 형식으로 그 회사 웹에서 제공하고 있어요.


그런데 회사사람들 대부분이 블랙베리 폰을 사용하고 있어서 구형 BB 에서는 PDF 형식을 보여주기가 힘들거든요.


그 회사랑 따로 EDI 시스템 개발해서 데이터 주고 받고 하는 번거로운일을 하지 않고 그냥 그 회사에서 제공하는 메뉴에서 우리가 필요한 데이터만 추출해서 서비스하는 방법을 고민중입니다.


일단 인터넷 서핑을 통해서 PDF 를 TEXT 로 바꿔주는 소스코드는 구했습니다.

이 소스코드를 한번 분석해 보고 어떤 방법이 있을지 없을지 알아보려구요.




메뉴는 이렇게 생긴 PDF 파일인데요.

왼쪽의 내용들은 필요 없고 오른쪽에 있는 요일별 메뉴들만 뽑고 싶거든요.


원본 pdf 파일과 이 내용을 text 로 바꿔주는 PHP 파일은 여기 있습니다.



original.pdf

pdf2text.php


이걸 돌리면 결과가 아래와 같이 나옵니다.



흠 다 텍스트로 나오긴 나왔는데 이거 가지고는 따로 메뉴만 추출해 내기 쉽지 않네요.

이렇게 모두 한줄로 나오는게 아니라 라인별로 따로 출력이 돼면 좀 더 낫지 않을까요?


일단 pdf2text.php 를 분석해 봐야 겠습니다.


pdf2text.php 파일 안에는 9개의 함수가 있습니다.



이 pdf2text.php 를 실행하면 제일 먼저 어떤게 실행될까요?

함수들은 어디서 호출을 해 줘야 실행되니까 다 그냥 건너뛰겠고...

$result = pdf2text ('original.pdf'); 가 제일 먼저 실행되겠죠?


이건 pdf2text($filename) 함수를 call 하는 겁니다. 거기서 처리된 값을 $result 변수에 담고 그 내용을 echo 함수로 브라우저에 뿌려주는게 이 프로그램이 하는일의 전부 다 입니다.


이제 그 중간의 처리 과정을 자세히 공부해 보겠습니다.


우선 pdf2text($filename) 함수는 아래와 같습니다.


function pdf2text($filename) {
// file_get_contents return the contents of a file as a string
    $infile = @file_get_contents($filename, FILE_BINARY);
    if (empty($infile))
        return "";

    $transformations = array();
    $texts = array();

    preg_match_all("#obj(.*)endobj#ismU", $infile, $objects);
    $objects = @$objects[1];
   
   

    for ($i = 0; $i < count($objects); $i++) {
        $currentObject = $objects[$i];
//echo $currentObject . "<p> end";
        if (preg_match("#stream(.*)endstream#ismU", $currentObject, $stream)) {
            $stream = ltrim($stream[1]);
//echo $stream . "<p> end";
            $options = getObjectOptions($currentObject);
            if (!(empty($options["Length1"]) && empty($options["Type"]) && empty($options["Subtype"])))
                continue;

            $data = getDecodedStream($stream, $options);
            if (strlen($data)) {
                if (preg_match_all("#BT(.*)ET#ismU", $data, $textContainers)) {
                    $textContainers = @$textContainers[1];
                    getDirtyTexts($texts, $textContainers);
                } else
                    getCharTransformations($transformations, $data);
            }
        }
    }

    return getTextUsingTransformations($texts, $transformations);
}

맨 처음으로는 해당 파일의 내용을 받아옵니다. 이것은 바이너리 형식이라서 사람이 읽을 수 있는건 아닙니다. ($infile = @file_get_contents($filename, FILE_BINARY);)

그 내용을 출력해 보면 아래와 같이 나옵니다.



이걸 보면 헤더정보만 사람이 읽을 수 있는 텍스트죠?

이 문서는 PDF 1.5 버전이라는 것을 알 수 있습니다.

그리고 이 헤더정보는 endobj 부분에서 끝나는 겁니다.
나머지는 사람이 읽을 수 없는 바이너리 형식입니다.

그 다음 if 문에서는 해당 파일이 비어있는건지 봅니다. 비어있으면 나머지 로직을 실행할 필요가 없겠죠? 괜히 시간만 낭비니까 그 cost 를 줄이기 위해 비어있으면 그냥 return 을 해 버립니다.


파일이 empty 가 아니면 그 다음을 실행할 텐데요.

(참고로 if 문의 {} 가 없습니다. 그 안에 내용이 단 1줄이면 {} 없이 사용할 수 있습니다.

그러면 바로 그 다음줄까지만 if 절 안에 포함돼 있는 겁니다.)


그 다음은 $transformations 라는 배열과 $texts 라는 배열을 만들어 줍니다.


오늘은 여기까지만 하고 다음에 계속 분석해 보겠습니다.

지금 토요일 아침 7시 40분인데요.

가족이랑 어디 가기로 해서 지금 나가봐야 되네요.


여행 다녀와서 계속 공부할텐데 그 내용도 여기 정리해 놓을께요.



반응형

Comment

PHP와 XSL 로 XML 변환하기

2012. 12. 20. 12:31 | Posted by 솔웅


How to parse XML with PHP5




Feeds 는 content 의 stream 으로 사람들이 웹사이트를 통해 정보의 조각들을 공유하기 위해 만든 것입니다. PHP5의 simpleXML 함수는 이 feed를 웹페이지에서 사용하기 편하도록 interpret 하는 방법을 아주 간단하게 구현할 수 있도록 도와 줍니다.


저는 최근 저희의 라디오 방송국 playlist 에서 제공하는 노래에 대한 live feed를 display 하는 widget 과 관련해서 작업을 했었습니다. radio 방송국에서 운영하는 시스템에서는 XML을 제공하는데요 이 자료들은 데이터베이스에서 나옵니다. 프로그램은 그 데이터를 feed로 만들어서 제공합니다.






서로 다른 서버끼리 데이터를 공유하기 위해 XML 을 사용하는 것은 일반적인 방법입니다. playlist 를 generate 하는 시스템은 proprietary 입니다. XML은 어떤 데이터가 공유될 수 있도록 하는 easy format 을 제공합니다.


XML 은 뭘까요?


XML 은 eXtensible Markup Language 의 줄임말로 site들 사이에서 공유하기 위해 데이터를 structure 하는 방법입니다. RSS (Real Simple Syndication) 와 Podcasts 같은 기술들도 XML 의 특별한 형태입니다. XML이 좋은 점은 여러분이 필요로 하는것을 여러분이 원하는 대로 표현할 수 있다는 겁니다.



XML은 쉽게 생성할 수 있습니다. 왜냐하면 HTML 이랑 아주 비슷하거든요. HTML 과 다른 점은 여러분만의 tag 를 따로 만들 수 있다는 겁니다. 예를 들어 여러분의 라디오 방송국에서 틀어줄 노래들의 list 에 대한 feed 를 put 한다고 가정합시다. 그러기 위해서 할 일은 당지 artist 이름, 노래 제목, 노래가 방송된 시긴 등을 encode 합니다. 이와 관련된 tag들을 만들 겁니다. <title> <artist> 그리고 이것들은 <song> tag 가 감쌀 겁니다. 또 우리는 각 노래가 방송된 시간을 표시할 건데요. 날짜와 시간이 여기에 들어갈 겁니다.

여러분은 이것을 아래 처럼 encode 할 수 있을 겁니다.


<songs>
    <song dateplayed="2011-07-24 19:40:26">
        <title>I left my heart on Europa</title>
        <artist>Ship of Nomads</artist>
    </song>
    <song dateplayed="2011-07-24 19:27:42">
        <title>Oh Ganymede</title>
        <artist>Beefachanga</artist>
    </song>
    <song dateplayed="2011-07-24 19:23:50">
        <title>Kallichore</title>
        <artist>Jewitt K. Sheppard</artist>
    </song>
</songs>



여기서 XML 데이터를 만들 때 지켜야 될 몇가지 규칙이 있습니다. 만약 XHTML 에 대해 잘 아신다면 쉽게 이해가 가실겁니다. 한번 볼까요?

   *  XML is case sensitive so <Title>` is not the same as <title>.
   *  All XML elements must have closing tags.
   *  XML requires a root element (the <songs> tag above serves as our root element)
   *  Attributes must be quoted
   *  Special characters (like & (&amp;) and < (&lt;) and > (&gt;) signs) must be encoded.

XML 은 HTML 보다 좀 더 strict 합니다. 하지만 정말 만들고 다루기가 쉽습니다.




Introducing simpleXML



simpleXML 을 사용해서 XML을 아주 쉽게 읽어서 그 내용에 접근할 수 있습니다.

위에 있는 XML 을 songs.xml 로 저장했다고 칩시다. 같은 폴더에 php 파일을 만들 겁니다.

이 전체 XML 을 아래 코드를 사용해서 읽을 겁니다.


<?php
    $mysongs = simplexml_load_file('songs.xml');
?>



이렇게 하면 다 읽은 겁니다. 저 xml 파일이 웹상의 어딘가에 있어도 그 URL 만 가지고 이렇게 읽을 수 있습니다. xml 파일이 여러분 서버에 있을 필요도 없는 거죠.

이제 우리는 이 파일의 내용을 담은 object (객체)를 가지게 됐습니다.

이 song 객체는 $mysongs 라는 변수에 담겨져 있습니다. 만약에 첫번째 artist 의 이름을 출력하고 싶다면 이렇게 하시면 됩니다.


<?php
    $mysongs = simplexml_load_file('songs.xml');
    echo $mysongs->song[0]->artist;
?>






이 객체의 일부분으로 XML tag 들이 매핑돼 있다는 걸 기억하세요. 그래서 그 name 을 통해 어느 element 이든 우리가 얻어 낼 수 있는 겁니다. 그리고 PHP 에서는 배열이 0번부터 시작한다는 것도 기억하시구요. 그래서 배열의 0번째 title을 위와 같이 출력한 겁니다.

자 이제 3번째 노래 제목을 출력해 볼까요?


<?php
    $mysongs = simplexml_load_file('songs.xml');
    echo $mysongs->song[2]->title;
?>





Working with Attributes



date 들을 얻으려면 그 attribute들에 어떻게 접근해야 되는지 알아야 됩니다. 이 notation은 tag 랑은 약간 다릅니다. 하지만 사용하는 건 똑 같이 쉽습니다.
바로 아래 처럼 사용하시면 됩니다.

<?php
    $mysongs = simplexml_load_file('songs.xml');
    echo $mysongs->song[1]['dateplayed'];
?>




Making a list of songs


So now that we’ve got the basics of accessing elements, let’s write the code to make a complete list of our songs parsed by interpreting our XML file.

이제 우리는 element들에 어떻게 접근하는지 그 기본을 알게 됐습니다.

이제 이 XML 파일을 interpret 함으로서 전체 노래를 parse 하도록 하겠습니다.


<?php
    $mysongs = simplexml_load_file('songs.xml');
    echo "<ul id="songlist">n";
    foreach ($mysongs as $songinfo):
        $title=$songinfo->title;
        $artist=$songinfo->artist;
        $date=$songinfo['dateplayed'];
        echo "<li><div class="title">",$title,"</div><div class="artist">by ",$artist,"</div><time>",$date,"</time></li>n";
    endforeach;
    echo "</ul>";
?>



각각의 노래들에 대해 접근하기 위해 우리는 foreach statement 를 사용했습니다. 그리고 그 정보를 간단한 HTML list 로 parsing 했습니다. 여러분은 이것을 일반적인 HTML 문서로 사용하시거나 아니면 노래 리스트를 출력하는 widget 으로 사용하실 수 있습니다.





Parsing a Flickr feed from a set


온라인에는 여러분이 parse 할만한 수 많은 XML feed 들이 있습니다. 예를 들어 Flickr 로부터 feed를 받을 수 있죠. 만약 여러분이 Flickr 를 update 하면 이 widget 은 자동적으로 이것을 여러분 웹싸이트에 display 할 겁니다.

예제로 사용하기 위해 약간의 고양이 사진들을 준비했습니다.
이 feed 에 대한 XML 을 얻으려면 Flickr 내의 웹 페이지로 가야 합니다. 그리고 화면 왼쪽 아래에 있는 XML icon 을 보세요.





우선 이 XML 의 구조를 알기 위해 이것을 분석해야 합니다. 이 feed 링크에서 오른쪽 마우스를 클릭해서 여러분의 하드 드라이브에 저장해 보세요. 그리고 이것을 photoset.xml 이라고 이름 짓고 브라우저로 열어 보세요.







저는 Safari 로 이 XML 파일을 열었습니다. 이 구조를 한번 살펴 보죠. 각각의 photo 들은 <entry> tag 안에 있죠? 그 안에 두개의 <link> tag 가 있네요. 첫번째 것은 Flickr 상의 이미지 링크이고 두번째 것은 이 이미지의 medium size 버전에 대한 링크가 있습니다.



위 예제를 살짝 바꿔보죠. 그리고 이 이미지들에 대한 thumbnail 을 표시하기 위해 두번째 link 를 살짝 조절하겠습니다. 이 작업을 하기 전에 Flickr 로 돌아가서 그 XML 파일의 경로를 얻으세요. 그리고 아래와 같이 코딩해 보세요.



<?php
    $mypix = simplexml_load_file('http://api.flickr.com/services/feeds/photoset.gne?set=72157627229375826&nsid=73845487@N00&lang=en-us');
    foreach ($mypix->entry as $pixinfo):
        $title=$pixinfo->title;
        $link=$pixinfo->link['href'];
        $image=str_replace("_b.jpg","_s.jpg",$pixinfo->link[1]['href']);
        echo "<a href="",$link,""><img src="",$image,"" alt="",$title,"" /></a>n";
    endforeach;
?>



<img> tag 의 alt text 로 <title> tag 를 사용할 겁니다. 그리고 anchor tag 의 href attribute 로 첫번째 <link> tag 를 사용할 거구요. 두번째 link 는 약간의 트릭을 사용했습니다. 두번째 링크의 href attribute ($pixinfo->link[1]['href']) 를 얻기 위해 array notation 을 사용할 수 있습니다. 그렇게 해서 우리가 필요한 큰 이미지를 얻게 될 겁니다. 이미지 이름을 바꾸기 위해서 str_replace 함수를 사용할 겁니다. 그러면 아래와 같은 thumbnail 을 얻게 될 겁니다.



Conclusion


simpleXML 은 정말 쉬워서 이것을 이용하면  Flickr 예제 같은 복잡한 feed를 parse 하는 것이 재밌을 겁니다. <entry> tag 안의 <link> tag 의 두번째 instance를 얻는데 아무런 문제가 없었던 점을 기억하세요. 이 작업은 이전 버전의 PHP 에서는 구현하기가 매우 어려웠을 겁니다. simpleXML 에는 다른 많은 기능들이 있습니다. 더 자세한 내용은 PHP manual을 보세요.
객체지향적인 접근에 관심이 있다면 PHP5 가 제공하는 SimpleXMLElement class도 도움이 될 겁니다.







반응형

Comment

PHP로 XML , JSON 다루기

2012. 8. 24. 05:14 | Posted by 솔웅


일하다가 동료가 처리할 데이터가 있는데 이 데이터를 어떻게 관리했으면 좋겠냐고 물어보더라구요.


XML 로 관리할지 JSON으로 관리 할지.....

저희 시스템은 PHP로 돼 있거든요.


그래서 일단은 JSON이 가장 가벼우니까 데이터를 파일로 관리하면 JSON으로 관리하는 법도 생각해 볼 수 있겠지만 데이터도 많지 않고 바뀌지도 않을 거고 그냥 a 가 1인 경우의 b 값을 화면에 출력만 하면 되니까 디비에 넣어서 관리하는게 제일 편하지 않을까 의견을 주었습니다.


다른 시스템간에 데이터를 인터페이스 할 것도 아니고....


하여간 그래도 그 얘기 듣고 PHP로 XML과 JSON을 처리하려면 어떻게 해야 하는지 그 구체적인 소스가 궁금해서 써핑 해 봤습니다.


* PHP 로 XML 다루기


<?xml version="1.0" encoding="utf-8"?>
<data>
    <total> 2 </total>
    <item>
        <name> Raj </name>
        <phone> 123456789 </phone>
        <age> 17 </age>
    </item>
    <item>
        <name> Akshay </name>
        <phone> 987654321 </phone>
        <age> 15 </age>
    </item>
</data>


이런 xml 데이터가 있을 때 php 코드는 아래와 같으면 됩니다.


<?php
 $xml_string = file_get_contents($_SERVER['DOCUMENT_ROOT'].'/data.xml');
 $xml = simplexml_load_string($xml_string);
 echo $xml->total . "<p>"; //2
 echo $xml->item[0]->name . "<p>";       // Raj
 echo $xml->item[0]->phone . "<p>";        // 123456789
 echo $xml->item[0]->age . "<p>";        // 17
 echo $xml->item[1]->name . "<p>";        // Akshay
 echo $xml->item[1]->phone . "<p>";         // 987654321
 echo $xml->item[1]->age;        // 15
?>


먼저 file_get_contents 로 data.xml 파일에 있는 모든 내용을 긁어 옵니다.

그러면 $xml_string 변수에 배열로 그 내용들이 담길 겁니다.


그 다음에는 복잡하게 코딩할 필요 없이 그냥 simplexml_load_string() 메소드를 사용하시면 됩니다.


그 안의 내용을 처리하는 방법은 $xml-> 다음에 원하는 내용이 있는 태그를 사용하면 됩니다.

total 은 한번만 있으니까 곧바로 얻어오고 그 다음 item 은 계속 반복되는 태그이니까 배열불러오듯이 불러오면 됩니다.


아래 샘플 파일 올려놓겠습니다.


data.xml


xml.php





* PHP 로 JSON 다루기


아래 코드도 어디에선가 긁어 온 건데요.


for(){
  $str[] = array('code'=>$bbs_no,'table'=>$table_type);
}

----------------------
code[0]      table[0]
code[1]      table[1]
----------------------

이렇게 데이터들이 담길 겁니다.

$jsonStr = json_encode($str); // ******* Make Json from array ********
<input type="hidden" name="json_list" id="json_list" value=$jsonStr  /> // Send Form


유저로부터 데이터를 입력받아서 이것을 json으로 encode 한 겁니다.


그러면 이 json 값을 한꺼번에 form 테그에서 send 할 수가 있습니다.


그 다음 받는 파일에서는 아래와 같이 처리하면 됩니다.


$json_list = $_REQUEST['json_list']; //get Form
$json_list = str_replace('\\', '', $json_list);
json_list= json_decode($json_list, true); // Decode json
echo $json_list[0]['code'];
echo $json_list[1]['table'];


간단하네요.


나중에 유용하게 사용될 수 있을 것 같습니다.


반응형

Comment

  1. 야생 2012.09.08 19:19

    감사합니다. 덕분에 잘 배우고 갑니다 ^^


아래 글은 http://hardboiledwebdesign.com/ 을 만든 앤디가 자신이 몇개월간 작업하면서 만들어 놓은 CSS3 Media Query  관련 소스를 공개한 글 입니다.

앞으로 반응형 웹 작업을 하게 되면 아주 유용하게 쓰일 것 같습니다.

좋은 정보를 공유해 준 앤디에게 감사하면서 이 정보를 제 블로그에 정리해 둡니다.


Hardboiled CSS3 Media Queries

제가 책을 launch 하기 위해  Hardboiled Web Design 웹사이트를 만들면서 CSS3의 Media Query를 사용해서 responsive layout을 만드는 것은 아주 많은 일을 해야 되는 작업이었습니다.

지난 몇달간 Media Query를 사용하면서 각 프로젝트마다 여러번 그 소스들을 고쳤었습니다. 그래서 아예 표준문안처럼 만들어 놓으면 다음에 사용할 때 편할거라고 생각했죠.

이 hardboiled CSS3 Media Queries들은 각 디바이스들에 대한 empty placeholder들 입니다. 이걸 이용하면 당장 responsive 디자인을 시작할 수 있죠.

이것은 책을 내면서 같이 선사하는 toolkit이었습니다.

그리고 여러분들은 지금 이 소스를 다운로드 받으시고 오버라이드해서 마음대로 사용하실 수 있습니다.


Download the CSS file




/* Smartphones (portrait and landscape) ----------- */ @media only screen and (min-device-width : 320px) and (max-device-width : 480px) { /* Styles */ } /* Smartphones (landscape) ----------- */ @media only screen and (min-width : 321px) { /* Styles */ } /* Smartphones (portrait) ----------- */ @media only screen and (max-width : 320px) { /* Styles */ } /* iPads (portrait and landscape) ----------- */ @media only screen and (min-device-width : 768px) and (max-device-width : 1024px) { /* Styles */ } /* iPads (landscape) ----------- */ @media only screen and (min-device-width : 768px) and (max-device-width : 1024px) and (orientation : landscape) { /* Styles */ } /* iPads (portrait) ----------- */ @media only screen and (min-device-width : 768px) and (max-device-width : 1024px) and (orientation : portrait) { /* Styles */ } /* Desktops and laptops ----------- */ @media only screen and (min-width : 1224px) { /* Styles */ } /* Large screens ----------- */ @media only screen and (min-width : 1824px) { /* Styles */ } /* iPhone 4 ----------- */ @media only screen and (-webkit-min-device-pixel-ratio : 1.5), only screen and (min-device-pixel-ratio : 1.5) { /* Styles */ }

물론 하나의 스타일쉬트 파일에 방대한 responsive design style들을 넣고 싶지 않으실 겁니다.

이럴 경우 여러 스타일쉬트 파일로 소스를 구분하시고 html 파일에서 link element를 사용하시면

좋으실 겁니다.

<head>

<link rel="stylesheet" href="smartphone.css" 
media="only screen and (min-device-width : 320px) 
and (max-device-width : 480px)">

<link rel="stylesheet" href="smartphone-landscape.css" 
media="only screen and (min-width : 321px)">

<link rel="stylesheet" href="smartphone-portrait.css" 
media="only screen and (max-width : 320px)">

<link rel="stylesheet" href="ipad.css" 
media="only screen 
and (min-device-width : 768px) 
and (max-device-width : 1024px)">

<link rel="stylesheet" href="ipad-landscape.css" 
media="only screen 
and (min-device-width : 768px) 
and (max-device-width : 1024px) 
and (orientation : landscape)">

<link rel="stylesheet" href="ipad-portrait.css" 
media="only screen 
and (min-device-width : 768px) 
and (max-device-width : 1024px) 
and (orientation : portrait)">

<link rel="stylesheet" href="widescreen.css" 
media="only screen and (min-width : 1824px)">

<link rel="stylesheet" href="iphone4.css" 
media="only screen 
and (-webkit-min-device-pixel-ratio : 1.5), 
only screen and (min-device-pixel-ratio : 1.5)">

</head>

Download the CSS file and any comments or suggestions for future improvements would be more than welcome.

Sign-up for email alerts or follow @itshardboiled for more updates and sneak previews.



반응형

'etc. > Responsive Web' 카테고리의 다른 글

자바스크립트 기초 메모  (0) 2016.03.24
반응형 웹 Media Query 를 위한 CSS 탬플릿 자료  (0) 2012.07.28

Comment


지금 회사에서 사용하고 있는 Kurogo 가 PHP 로 돼 있거든요.


그래서 그 시스템을 커스터마이징을 하려면 PHP 코딩을 해야되서...

거의 10여년만에 PHP를 다시 보고 있습니다.


중간 중간 기억하고 싶은 팁들이 생기면 여기다 저장해 놓으려구요.


일단 지금은 원격 서버의 이미지 파일을 저희 팀 웹페이지에 display 하는 로직을 만들고 있는데요.


우선 그 이미지가 있는지 없는지부터 확인해서 있으면 표시하고 없으면 다른 메세지나 디폴트 이미지를 하기로 했습니다.


이미지 파일이 있는지 없는지를 확인할 수 있는 방법으로는 첫번째로 이미지의 크기를 구하는 함수를 사용할 수 있습니다.


//// check Image size       
        function checkIMG($IMGPath) {
            $fileCheck = getImagesize($IMGPath);
            if($fileCheck) { $isExist = "OK"; } else { $isExist = "NO"; }
            return $isExist;
        }


함수에 원격 이미지 파일의 경로와 파일이름을 담은 $IMGPath 를 넘겨주면 됩니다.





두번째로는 이미지이외에도 다른 경우에도 사용할 수 있는 건데요. 헤더 정보를 얻는 겁니다.

//// get header info
        function checkHeader($filePath) {
            $AgetHeaders = get_headers($filePath);
            if(!$AgetHeaders) {
                echo "Network Problem. Too slow or No Network.<p>";
                $isExist = "Net";
            } else {
                if (preg_match("|200|", $AgetHeaders[0])) {
                        // file exists
                    $isExiset = "OK";
                } else {
                        // file doesn't exists
                    $isExiset = "NO";
                }
            }
            return $isExiset;
        }


여기선 중간에 살짝 정보를 얻어오지 못할 경우 Network 문제가 있다고 뿌려주는 로직도 있습니다.


그 다음으로는 cURL을 사용하는 건데 이건 정확히 get_headers()와 뭐가 다른지 모르겠네요.

cURL로는 파라미터 정보를 넘길수도 있다고 하는데...

하여간 사용법은 아래와 같습니다.


////////
        function curl1($filePath) {
            $curl = curl_init();
            curl_setopt_array( $curl, array(
                CURLOPT_RETURNTRANSFER => true,
                CURLOPT_URL => $filePath ) );
            curl_exec( $curl );
            $response_code = curl_getinfo( $curl, CURLINFO_HTTP_CODE );
            curl_close( $curl );
            return $response_code;
        }       
       
        function curl2($filePath){
            //To get the whole header you can issue a HEAD request, like this:

            $curl = curl_init();
            curl_setopt_array( $curl, array(
                CURLOPT_HEADER => true,
                CURLOPT_NOBODY => true,
                CURLOPT_RETURNTRANSFER => true,
                CURLOPT_URL => $filePath ) );
            $headers = explode( "\n", curl_exec( $curl ) );
            curl_close( $curl );
           
            return $headers[0];
        }


그런데 위 4가지 방법 모두 다 문제가 있었습니다.

왜냐하면 회사 서버에 Proxy 가 있는데 이걸 통해서는 아무 값도 못 받아오더라구요.


회사 내부 서버끼리 테스트 할 때는 잘 됐는데 회사 네트워크 밖에 있는 이미지(파일)을 가지고 하려니까 안되더라구요.


이럴 경우 Proxy 를 거쳐서 정보를 가져오도록 해야 되는데요.

stream_context_create() 함수와 file_get_contents() 함수를 사용했습니다.


/////// get contents via proxy               
        function getViaProxy($filePath){
                                // Define a context for HTTP.
                    $aContext = array(
                        'http' => array(
                        'proxy' => '프락시 정보', // This needs to be the server and the port of the NTLM Authentication Proxy Server.
                        'request_fulluri' => True,
                    ),
                    );
                    $cxContext = stream_context_create($aContext);

                    // Now all file stream functions can use this context.
                    $sFile = file_get_contents($filePath, False, $cxContext);
                    if($sFile){
                        $result = "Y";
                    }else{   
                        $result = "N";
                    }
                    return $result;
        }


이렇게 해서 어렵게 어렵게 문제를 해결했습니다.


반응형

Comment


How do I unset the clean URLs?

Last updated March 18, 2011. Created by dman on February 2, 2004.
Edited by mr.baileys, jonhattan, jwuk, greggles. Log in to edit this page.


clean URLs를 하지 않고 두루팔을 옮긴 경우가 발생할 수 있습니다. 그러면 모든 링크는 제대로 작동하지 않을 겁니다. 왜냐하면 이미 생성된 path는 hosting platform에 의해 지원되지 않기 때문이죠.


This occasionally happens아래의 경우도 발생할 수 있습니다.

  • 호스트 간 데이터베이스를 transfer 한 이후
  • local copy를 한 이후
  • 백업에서 restoring 한 이후 (.htaccess 가 없을 경우)
  • .htaccess 가 지워진 경우
  • 혹은 여러분 호스트에서 원하지 않은 security change가 있는 경우


문제는 여러분은 세팅을 할 수 없게 됐다는 겁니다. 왜냐하면 configuration page를 더이상 링크해서 들어갈 수 없기 때문이죠.

드루팔 (Drupal)은 여러분이 해당 링크에 접근하도록 하기 전에 먼저 clean URLs 가 지원되는지 부터 체크 하고 계속 작업이 이루어 질 수 있는지 여부를 체크합니다.




이 문제를 해결의 가장 간단한 방법은 unclean 시스템 path를 직접 entering 하는 겁니다.

여러분 스스로 lock 됐다면 아래 경로를 통해서 접근하세요.
http://example.com/?q=user

그 페이지에서 여러분은 로그인을 할 수 있습니다. 그러면 admin 권한을 받을 수 있겠죠. 아직까지 모든 링크는 작동하지 않을 겁니다.

다음으로는 아래 url로 접근하세요. (Drupal 5와 Drupal 6 의 경우). 그러면 여러분이 unset clean URLs를 할 수 있는 페이지를 보실 수 있을 겁니다.
http://example.com/?q=admin/settings/clean-urls

이제 여러분은 사이트를 제대로 이용할 수 있을 겁니다. 링크가 제대로 걸릴 테니까요.

Other options that should get the same result include:

다른 방법도 있습니다.

  • Drush command를 실행하세요.

    drush vset clean_url 0 --yes

  • mysql command를 실행하세요.

    UPDATE variable SET value = 's:1:"0";' WHERE name = 'clean_url';
    DELETE FROM cache;
  • 혹은 settings.php를 수정하셔도 됩니다.
    $conf['clean_url'] = 0;


반응형

Comment

두루팔 옮기기 2 - 체크 리스트 -

2012. 7. 18. 05:43 | Posted by 솔웅


Checklist for migrating to a new server

Last updated October 31, 2011. Created by dman on November 13, 2008.
Edited by xamount, Kami Petersen. Log in to edit this page.




두루팔을 새로운 호스트로 옮기고 사이트를 활성화 할 때 살펴봐야할 것들이 있습니다.

이 체크리스트는 이미 로컬이건  호스트된 서버이건 사이트가 돌아가도록 하는데 성공했지만 다른 host나 architecture에 이 사이트를 옮겨야 할 필요가 있는 사람들을 위해 쓴 글입니다. 서버별로 그리고 버전별로 조금 다를 수가 있습니다. 그러니까 옮기고 난 이후에 겉으로 잘 돌아가는 것 처럼 보여도 여러 테스트를 해야 합니다. 

아래 체크 리스트들이 많은 것 처럼 보이지만 이 리스트 들 중 대부분인 이미 제대로 세팅 돼 있을 겁니다. 하지만 옮긴 이후에 체크를 해서 문제 없다는 것을 확인 해야 이후에 발생될 여러 문제점을 예방할 수 있습니다. 여러분들 중 대부분은 아래 작업을을 해 보셨겠지만 사이트를 옮긴 후에 이 작업을 반복해서 해야 합니다. 이 체크리스트대로 하지 않고 이미 업로드를 해 버렸고 제대로 작동하지가 않는다면 unset clean-urls 를 manually 해야 합니다.



Server basics


Drupal UI

  • TEST an upload.
  • TEST an image derivative rebuild.
  • Review access control settings for admin/editor/authenticated/anonymous users.
    각 role 별로 로그인을 한 후 체크하세요. big file을 업로드 할 수 있는지 input filter 등을 사용할 수 있는지 등등.


Permissions checks

  • Adjust write-access to sites/${SITENAME} (if installing) and sites/${SITENAME}/files
    • Check at admin/settings/file-system, it'll warn you if there's a problem.
    • What you need to do and what you CAN do to adjust permissions on the server will vary between systems.
  • check write-access to /tmp . Change it to sites/${SITENAME}/files/tmp (no leading slash) if needed.


Security tweaks

  • 셋업을 하고 난 후 모든 코드가 security 때문에 read-only  되 있는지 체크해 보세요.
    See more at File Permissions and Ownership For Security.
  • 새롭게 생성된 파일과 폴더의 owner와 group을 확인하세요. Check the owner and group of any newly created files and folders
    ls -la files/
    If the owner of web-process created files is the same as your login username (not www-data), that means it's theoretically possible for web scripts to modify themselves. This is a hack vector, and could be a concern.
  • settings.php 를 체크하세요. 여기에 database 암호가 text로 돼 있습니다. 이 파일의 접근 권한을 보고 모두에게 readable 돼 있지 않나 살펴 보세요. 만약에 그렇게 돼 있으면 웹을 통해서 여러분 디비의 암호가 노출 될 수 있습니다.
    For this reason, it would be good to have your :
    - Admin-control panel-ssh login password different from your
    - database password different from your
    - Drupal user #1 password.
    ...even though that's a pain.
  • If you have enough rights, consider shifting htaccess directives into apache configuration files for performance.
  • Remove phpinfo.php if you had one.


Testing

  • TEST directory browsing is disabled for files/ (by attempting to access it in a browser)
  • TEST that www.example.com and example.com perform the same, preferably by redirecting one to the other. See .htaccess [handbook doc needed?]
  • TEST email sending. Email setup is different for different hosts, but should be configured already by the sysadmin.
  • Check the email:from headers and see what you can do to avoid system emails going into a spam bucket
  • More testing ideas.


Best Practice Extras

  • Run a links checker. Xenu is simple for windows. linklint is adequate for commandline.
  • Visit your admin/reports after running a link checker and see what shows up. Other errors, not just 404s may appear there and need attention.
  • Consider benchmarking Drupal Performance. apachebench (ab) is OK, but needs root and just whacks one page. siege is better (can script a session), but needs installing.
  • If you have a high level of control on the server, Consider other tuning issues like PHP accelerators.
  • Consider your backup plan.
  • TEST your backup recovery.
  • Remember to configure and test any non-Drupal logging tool you may want to use. eg, Webalizer, Google Analytics or something provided by your host.
    Now is a good time to locate your server logs, and make sure you have access to them from your host. When you need them to troubleshoot problems it's too late to find that they don't exist.
  • Document every password, path and IP you can find. Domain registration, Control Panel login, User account info, FTP server, MySQL connection string, location of the config files for your backups, contact details for key parties etc. Put it all in a document with a DATE in it. Print that off and save it in three SAFE places.
  • Review your hosts policies on overages. It's much better if your host provides a warning & throttle service when/if you overrun your bandwidth or storage allocation than if they let it run then charge and penalize you (or just shut you down). Some hosts also punish 'excessive' use of the database or processor - which Drupal can be guilty of. Read the fine print.


반응형

Comment

두루팔 옮기기 1 - Drupal Migrating a site -

2012. 7. 17. 06:34 | Posted by 솔웅


지금 사용하던 Drupal 을 다른 곳으로 옮겨야 됩니다.
두루팔 사용경험이 하나도 없어서 부랴부랴 정보 researching 하고 있습니다.

혹시 두루팔을 A 서버에서 B 서버로 Migration 하는 방법 아시는 분 있으면 정보 부탁드립니다.



Last updated April 13, 2012. Created by LeeHunter on April 20, 2010.
Edited by John_B, sebastianSue, vj_pdx, ajspadial. Log in to edit this page.


만약 host를 바꾼다던가 개발서버와 실제 서버를 분리해서 관리를 할 경우에는 Drupal site를 migrate 할 필요가 있을 겁니다. 이 글은 이 일에 대한 outline 입니다. (아마 체크리스트라고 해야 할 것 같습니다.) 하지만 다른 곳에서는 제대로 묘사되지 못한 몇가지 스텝들도 포함돼 있습니다. 여러분들은 여러분들이 사용하는 모듈과 여러분 서버의 환경에 따라 이 스텝들을 약간씩 수정할 필요가 있습니다.

아래 과정은 한개의 site에 대한 과정을 담고 있습니다. Multi-site migration (Windows/Apache와 Linux) 은 다른 곳에서 다뤄지고 있습니다.


Before You Start


두개의 서버에 있는 PHP installation의 차이점을 정리해 두세요. (버그들이나 기능, 모듈, configurations, version 등등). 그리고 MySQL과 Apache 에 대해서두요.

파일을 업로드하고 다운로드하고 압축된 파일들을 다루고 퍼미션과 ownership을 수정하고 MySQL을 다루고 하는데 필요한 적절한 툴들을 준비하세요. 이런 스텝들을 다루는 Drupal tools들이 몇개 있습니다. 예를 들어 데이터를 백업하고 restoring 하는 것들 같은거요. 그렇다고 모든 과정을 다 처리해 주지는 않습니다. 여러분들이 아래 과정을 진행하는데 도움을 주는 툴이 있으면 사용하시고 아니면 그냥 직접 다 하셔도 됩니다.

새로운 사이트로 migrating 하기 위한 체크 리스트 - target site에서 두루팔이 필요로 하는 모든 기능 (mod_rewrite, AllowOverride) 등을 모두 지원하고 있어야 합니다. 전부 지원해 주는 호스트에서 조금 지원해주는 호스트로 옮기면 제대로 작동하지 않을 겁니다. 이건 migration에서 뭔가 잘못되지 않아도 target host의 세팅에 문제가 있으면 제대로 작동하지 않을 수 도 있다는 것을 말합니다.



On the old site

  1. 사용된 모듈과 버전 그리고 path 같은 것들을 정리해 두세요. contributed module site documentation이 이런 작업을 쉽게 할 수 있도록 할 겁니다.
  2.  admin/settings/file-system에서 사용될 수 있도록 temporary directory folder를 정리해 두세요. 그리고 database를 restoring 하고나서 수정할 수 있도록 준비해 두세요. 두 site 무도에 same path 가 존재하고 있어야 합니다.
  3. site maintenance mode를 세팅하세요 : Administer -> Site maintenance, Off line 선택
  4. 두루팔 core와 모듈을 최신버전으로 업데이트 할것인가에 대해 migration 하기 전에 결정하세요.
  5. Clean URLs를 Turn off 하세요. (Administer -> "Clean URLs") . 이제부터 www.example.com/?q=user 를 통해 administrator 부분으로 들어가게 될 거라는 것을 기억해 두세요. ("user"는 다른 유저 이름에 의해 replace 되지 말아야 합니다.)
  6. cache tables로부터 데이터를 clear 해 주세요. 이 데이터들은 transfer 에 필요하지 않은 데이터들입니다. 그리고 데이터를 정리할 때 혼란을 야기시킵니다. devel 모듈과 admin menu module 에는 이것을 쉽게 할 수 있는 link를 포함하고 있습니다. 다른 방법으로는 www.example.com/admin/settings/performance 로 가서 페이지 아랫쪽에 있는 Clear cached data 버튼을 누르세요.
  7. database를 Export 하세요. MySQL Administrator나 phpMyAdmin 을 사용해서 export 할 수 있습니다. 이렇게 해서 .sql 확장자를 가지는 text 파일로 된 데이터베이스 정보를 가질 수 있습니다.


    • MySQL Administrator 에서 우선 패스워드를 사용해서 접속하시고 왼쪽의 Backup 버튼을 누르세요. Databases 리스트에서 save하기를 원하는 데이터베이스를 선택하세요. 큰 화살표를 누르세요. 그러면 데이터베이스 이름을 오른쪽에 있는 네모칸인 Backup content 로 옮길 겁니다. 그 다음엔 오른쪽 아래에 있는 Start backup 버튼을 누르세요. 저장할 폴더를 선택하시고 이 때 윗쪽의 path par와 왼쪽의 Folders 리스트를 사용하시면 됩니다. 그리고 OK 버튼을 누르세요.
  8. 이전의 site 가 public (web에서) 이면 여러분 site를 on line으로 하는 것을 고려해 보세요. :  Administer -> Site maintenance 에서 on Line을 선택하시면 됩니다. 이제 예전 서버에서 만들어진 모든 modification은 잃어버릴 겁니다. (readers' comments, forums posts 등 등). 그러므로 여러분의 old website를 on line으로 set back 하시고 웹에서 public이라면 새로운 유저가 입력한 새로운 comments 등이 유실되지 않도록 new comments를 block 하면 좋을 겁니다 Administer -> Permissions.
  9. 모든 Drupal code를 copy 하세요. core, modules,themes 등을 copy 하고나서 필요하면 다운로드를 받으세요. 아니면 곧바로 새로운 서버로 transfer 하셔도 됩니다.
  10. files 디렉토리와 비슷한 다른 directory (image galleries 등)들도 copy 히세요. 그리고 다운로드 하시던가 새로운 서버에 곧바로 transfer 하세요.


In between

이 과정들은 old/new server와는 다른 여러분의 컴퓨터에서 수행 되어 질 겁니다. 만약 old 나 new 서버에서 작업하는 것이 더 쉽다면 그렇게 하셔도 됩니다. 쓸데 없이 다른 컴퓨터에 파일들을 복사해 넣을 필요는 없으니까요.

데이터베이스의 데이터들은 hard code 된 링크들을 가지고 있을 겁니다. 이런 링크들은 새로운 사이트에서는 필요가 없겠죠. 이것들을 수정하기 위해서 새로운 데이터베이스에서 SQL query를 사용하실 수 있습니다. 혹은 .sql 파일에서 직접 수정을 하실 수도 있겠죠. 이 작업을 하시면서 아래 내용들을 고려하세요.

  1. files table 에 있는 filepath field 의 files list.
  2. 사이트 URL - 많은 node 링크들과 reference들이 full site URL을 참조합니다. 그리고 많은 log file들을 참조하기도 하죠. 그렇기 때문에 new site의  name으로 바꾸는 것이 항상 적당한 것은 아닙니다. 그러니까 이 작업을 각각의 테이블단위로 하시고 고민하세요.
  3. 위 내용들을 variation 하세요. 예를 들어 messaging module은 messaging store에 각각의 message에 대한 site URL을 저장합니다. 그리고 imagefield 모듈은 filelist 같은 리스트가 있지요.
  4. 새 데이터베이스를 create 하기 위한 facility들 (아래의 Import Your SQL data를 보세요.)
  5.  데이터베이스 이름. 호스팅 회사에서는 모든 데이터베이스 이름 앞에 yourName_ 를 붙이도록 할수도 있습니다. 그리고 데이터베이스 이름에 들어가는 text 갯수를 제한할 수 도 있습니다.
  6. 아래 command는 두루팔을 A site에서 B site로 옮길 때 옮겨질 필요가 없는 데이터베이스의 데이터를 strip 하게 할 수 있습니다.
    sed -E -e "/^INSERT INTO \`(cache|watchdog|sessions)/d" < /path/to/dump.sql > /path/to/dump-stripped.sql
    만약 여러분의 database가 table prefix를 사용한다면 이 명령어를 약간 수정하실 필요가 있을 수도 있습니다.

만약에 실제 운행되고 있는 live site 에서 move 하거나 또는 live site로 move 한다면 여러분은 DNS 세팅을 수정해서 새 서버에 pointing 할 수 있도록 해야 할 필요가 있습니다.


On the new site


이제 new site에서 위의 과정을 거꾸로 진행하셔야 합니다.

  1. 전체 Drupal code (core,modules,themes) 를 new site로업로드 혹은 copy 합니다. 여러분이 원하시면 구조를 약간 바꾸셔도 되죠. 어떤 분들은 새 버전의 drupal core를 먼저 install 해서 새로운 server 환경을 테스트 하는 분도 계실겁니다.
  2. files directory나 비슷한 디렉토리들(image galleries 같은)를 업로드 혹은 copy 합니다. 업로드 혹은 copy 장소는 .sql 파일을 수정할 때 사용하게 될 위치가 되겠죠.
  3. 두루팔이 사용할 데이터베이스 유저를 생성합니다. 호스팅 회사에서는 여러분의 모든 데이트베이스 유저 이름 앞에 yourName_을 붙일 수도 있고 그 이름의 text 숫자에 제한을 둘 수도 있습니다. 여러분 호스팅 회사에서 create 쿼리를 허용한다면 .sql 파일 에 유저 생성 쿼리를 넣고 이 과정을 건너 뛰셔도 되겠죠.
  4. SQL data를 업로드하고 import 하세요. 데이터베이스를 직접 생성할 수 없다면 호스팅 회사가 제공하는 툴을 사용하실 수 있을겁니다. 이런 경우는 .sql 파일 안에 create database 라인을 지워주세요. (create database if not exist 라인은 상관없습니다.) phpMyAdmin으로 데이터베이스를 업로드하기엔 사이즈가 너무 클 수도 있습니다. 어떤 호스팅 회사는 MySQL Administrator로 접근할 수 있는 권한을 주기도 합니다. 그런 경우 용량이 큰 파일을 사용할 수 있습니다. SSH 접근을 가지고 있다면 text  console에서 MySQL을 사용하실 수 있을 겁니다. "mysql --user=user_name --password=your_password database_name" 그리고 sourch command도 사용하실 수 있겠죠. source database_backup.sql
  5. settings.php의 Database setting 섹션부분을 바꾸세요. 이 부분에서 new database로 경로가 설정 돼 있어야 합니다. 예전 서버와 다른 유저가 세팅 됐다면 유저도 제대로 설정해야 하구요.  패스워드도 마찬가지 입니다. 그리고 sub-domain과 domain level을 옮기셨다면 base URL을 수정하셔야 합니다.  그리고 $cookie_domain이 예전 도메인으로 설정돼 있지 않은지 체크하세요.
  6. 그리고 .htaccess 파일의 rewrite rule을 수정할 필요도 있습니다.
  7. new site로 log on 을 시도해 보세요. 아마 site maintenance mode와 non clean URLs의 combination에 의해 lock 돼 있을 겁니다. 이 경우에는 newsite/?q=user로 로그인을 하세요. 그리고 clean URLs를 turn on 하세요.
  8. site information부분을 수정하실 필요가 있습니다. (Administer → Site configuration → Site information). 여기에는 모든 email address 가 있습니다. 그리고 filedirectory를 (www.example.com/admin/settings/file-system) 파일이 새로 옮겨진 곳으로 바꿔 주세요. 또한 temp folder 도 다르다면 새로운 서버의 정확한 location으로 수정하세요. 
  9. 필요하다면 새로운 버전에 맞게 모듈들을 수정해 주세요. 예를 들어 PHP 5.2.8에서 5.3.0 으로 업그레이드 됐다면 어떤 모듈들은 제대로 작동하지 않을 수도 있습니다. 이럴 경우 여러곳에서 에러메세지를 보실 수 있을 겁니다. 아래 제가 search 한 에러의 내용들 입니다.

    • Set date.timezone = php.ini file안의 UTC  (아마 이 파일이 두개 있을 수 있는데요. 하나는 command line 용이고 다른 하나는 Apache 용인데 여러분의 경우엔 아파치용을 수정하셔야 할 겁니다.)
    • Apply patch 6.x-2.x-549884-30.patch to the date module
    • Use 6.x-3.x-dev instead of 6.x-3.0-alpha3 for the admin_menu module
    • Drush 와 함께 작동하지 않는 coder module을 delete 하세요. (하지만 이 부분이 항상 이 문제 때문인지는 확실하지 않습니다.)
  10. Check the status report: Administer → Reports → Status report. Drupal 에서 suggest 한다면 Cron을 Manually 작동시키세요.
  11. 이제 여러분의 new site는 예전 사이트 처럼 작동할 겁니다. 예전것과 구분하기 위해서 theme 이나 theme color를 바꾸고 싶을 수도 있을 겁니다.
  12. 필요에 따라 performance 파라미터도 수정하세요. Administer → Site configuration → Performance.
  13. 모든것을 다 체크했다면 site-maintenance mode를 turn off 하실 수 있습니다. : in Administer → Site configuration → Site maintenance, choose "On line".
  14. 여기서 설명한 대로 cron job을 셋업하세요. 이 크론은 어떤 컴퓨터에서든 온라인으로 run 할 수 있습니다. 여러분 PC에서도 가능합니다. 반드시 Drupal이 돌아가고 있는 서버여야 할 필요는 없습니다. 원하는 컴퓨터를 선택하세요. (항상 turn on돼 있고 on line  돼 있는 컴퓨터야 겠죠.) 만약 호스팅 컴퓨터가 크론 사용을 허용하지 않고 여러분에게 이 작업을 할 만한 컴퓨터가 없으면 Poormanscron 모듈을 사용하세요.
  15. 여러분의 새 두루팔 서버가 public으로 되기를 원하신다면 (예를 들어 WEB에 개방한다던지) 지금 DNS를 세팅해야 합니다. 여러분의 새로운 서버의 IP에 DNS를 세팅하세요. 이 작업을 하려면 domain name register를 contact 해야겠죠. 만약에 두루팔 사이트가 이미 웹에 있다면 그리고 여러분의 migrating이 public server에서 다른 곳으로 이뤄졌다면 이 register를 바꿀 필요가 있습니다. 이 경우에는  new registrar의 contract를 잘 읽어 보세요. 그리고 registrar를 바꾸기 전에 예전 registrar의 데이터베이스에 있는 DNS를 업데이트 하기를 추천합니다. TLD(top level domain)에 따라 (아마 EPP code, authorization code, Auth code라고 불리는 코드가 필요할 겁니다. 예전 registrar에 물어보세요. 그 다음에 이 코드를 새로운 registrar에 할당하세요. (아마 새로운 호스팅 회사를 통해서 가능할 겁니다.) 그 다음에는 기다리셔야 됩니다. 대가 5일 정도 시간이 걸립니다. 만약 이 작업에 아주 익숙하시다면 migration 작업 하기 전에 시간에 맞춰서 작업하셔도 되겠죠. 단지 여러분 작업이 완료되기도 전에 DNS transfer가 끝났다면 그 동안은 페이지 접근이 안되겠죠.



반응형

Comment

이전 1 ··· 3 4 5 6 7 다음