PHP로 출력되는 웹 페이지를 서버 측에서 PDF로 다운로드

10156 단어 PHPPDFheadless-chrome

요구사항


  • 특정 시스템의 관리 대시보드에서 보고서를 다운로드하고 싶습니다.
  • 보고서는 화면을 인쇄한 것과 동일하게 PDF로 한다.
  • 목록 페이지에 설치된 버튼 클릭으로 상세 페이지를 다운로드합니다.

  • 그림에 쓰면 이런 느낌.



    무엇을 사용하는가?



    헤드리스 Chrome 을 사용한다. 헤드리스 Chrome은 명령에서 Chrome 브라우저를 조작 할 수 있으므로 GUI 조작을 프로그램에서 실행할 수 있습니다.

    PDF를 만들려면


    google-chrome  --headless --no-sandbox --disable-gpu --print-to-pdf 'https://example.com/'
    

    좋다.

    몇 가지 문제


  • 인쇄 대상 URL에 액세스
  • 출력 대상
  • 글꼴

  • 헤드리스 Chrome을 사용하는 것이 좋지만 구현하는 데 몇 가지 문제가 발생했습니다.
    인쇄 대상이 로그인한 후의 페이지이기 때문에, 서버측으로부터 상세 페이지에 액세스 하려면 로그인 처리를 통과할 필요가 있어, 직접 URL에 액세스 할 수 없다. 또 출력처의 지정 방법을 모르거나 폰트가 없었다.

    1. 인쇄 대상에 액세스



    서버 측 헤드리스 Chrome에서 자신의 페이지에 HTTP를 통해 액세스하려고해도 로그인 처리를 통과하지 않았기 때문에 직접 액세스 할 수 없습니다.



    서버 측에서 자신에게 HTTP 경유로 액세스하는 것은 어렵지만, 출력 예정의 페이지의 HTML은 작성할 수 있다. 그래서 파일에 HTML을 출력하고 그것을 헤드리스 Chrome에 읽게함으로써 해결했다.
    HTML을 파일로 출력하고 있으므로 다음과 같이 PDF로 할 수 있다.
    google-chrome  --headless --no-sandbox --disable-gpu --print-to-pdf 'file:///path/to/page.html'
    

    2. 출력처 지정 방법



    이전의 명령 예로 실행했을 경우, PDF 파일은 명령을 실행한 디렉토리에 output.pdf 라는 이름으로 PDF 파일이 보존된다. 출력 대상을 지정하고 싶어도 google-chrome --help에서 도움말을 볼 수 없습니다. 그래서 소스 코드를 잡는다.
    // Default file name for pdf. Can be overriden by "--print-to-pdf" switch.
    const char kDefaultPDFFileName[] = "output.pdf";
    
    --print-to-pdf 로 덮어쓸 수 있다는 것이므로 --print-to-pdf=origin-file-name.pdf 로 출력처를 지정할 수 있는 것을 알 수 있다.

    3. 글꼴 설치 필요



    HTML 파일을 PDF화해도 일본어 폰트가 없으면 문자화되기 때문에 인스톨 할 필요가 있다. 일본어 폰트는 IPA 글꼴 로부터 다운로드할 수 있다.

    어떻게 할까



    1. 페이지 출력 HTML을 서버에 저장



    PHP에서는 출력 제어 함수을 사용하여 출력을 조작할 수 있다. 이번에는 서버에서 만든 HTML을 클라이언트에 반환하지 않고 서버에서 가져오고 싶기 때문에 이 함수를 사용한다.
    ob_start();
    /*
    ページを表示するための
    いろいろな処理
     */
    $html = ob_get_clean();
    

    이것으로 $html 변수에 출력 예정의 HTML이 보관 유지되고 나서는 이것을 서버에 보존하면 된다.
    MVC 모델의 프레임워크를 사용하고 있는 경우는 이런 느낌이 된다.
    Class Awesome extends Base_Controller {
        public function detail($id) {
            // 詳細ページの処理
        }
    
        public function pdf($id) {
            // 詳細ページの内容をPDFにしてダウンロードさせたい
            ob_start();
            $this->detail($id);
            $html = ob_get_clean();
    
            $html_filepath = "/tmp/" .  md5($html) . ".html";
            file_put_contents($html_filepath, $html);
        }
    }
    

    2. 저장된 HTML을 PDF로 저장



    이전 처리에서 저장한 HTML 파일을 헤드리스 Chrome을 사용하여 PDF화한다. 파일에의 액세스는 file:// 프로토콜로 지정하면 헤드리스 Chrome에 읽을 수가 있다.
    google-chrome  --headless --no-sandbox --disable-gpu --print-to-pdf="/tmp/output.pdf" "file:///tmp/detail_page.html"
    

    PHP의 코드에서는 exec() 함수를 사용하면 된다.
    $html = ob_get_clean();
    
    $html_filepath = "/tmp/" .  md5($html) . ".html";
    $pdf_filepath = "/tmp/" . md5($html) . ".pdf";
    
    file_put_contents($html_filepath, $html);
    
    exec("google-chrome  --headless --no-sandbox --disable-gpu --print-to-pdf=$pdf_filepath file://$html_filepath");
    

    3. IPA 글꼴 설치


    apt-get install -y unzip
    cd /usr/local/share/fonts/
    curl 'https://ipafont.ipa.go.jp/IPAfont/IPAfont00303.zip' -o IPAfont00303.zip
    unzip IPAfont00303.zip
    fc-cache -fv
    fc-list
    

    4. 다운로드하려면


    $pdf_filepath; // ダウンロードさせるPDFのファイルパス
    $basename = basename($pdf_filepath);
    
    header('Content-Type: application/pdf');
    header('Content-Disposition: attachment; filename="' . $basename .'"');//ファイルサイズを取得
    header('Content-Length: '.filesize($pdf));
    readfile($pdf);
    



    이 환경을 Docker로 만들려면 Chrome 설치나 폰트 설치가 필요하다. Dockerfile 는 이런 느낌이 된다.
    FROM php:5.6-fpm
    
    
    RUN cd /tmp
    RUN apt install -y gnupg
    RUN curl 'https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb' -o chrome.deb
    RUN curl 'https://dl.google.com/linux/linux_signing_key.pub' -o chrome_key.pub
    RUN apt-key add chrome_key.pub
    
    # 依存関係でエラーになるのでそれをインストールする
    RUN dpkg -i chrome.deb || apt-get install -f -y
    
    RUN dpkg -i chrome.deb
    RUN apt update
    RUN apt-get install -y google-chrome-stable
    
    # 日本語font install
    RUN apt-get install -y unzip
    RUN cd /usr/local/share/fonts/
    RUN curl 'https://ipafont.ipa.go.jp/IPAfont/IPAfont00303.zip' -o IPAfont00303.zip
    RUN unzip IPAfont00303.zip
    RUN fc-cache -fv
    RUN fc-list
    

    좋은 웹페이지 즐겨찾기