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

최근에 올라온 글

최근에 달린 댓글

최근에 받은 트랙백

글 보관함

카테고리


반응형

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


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() 메소드를 공부할 생각입니다.


그럼...


반응형