5
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

phpでmhtファイルを生成するには?

Last updated at Posted at 2014-09-11

概要

phpのみでmhtファイルを作成したい場合
以下のライブラリで実現できます
http://www.phpkode.com/scripts/item/mht-file-maker/

ライブラリの使い方

例えば "./cont/index.htm" ファイルをトップページとして
"./cont/" フォルダ配下のファイルを全部含むようにして
"./mht/cont.mht" ファイルを生成したい場合は…

make_mht.php
$MhtFileMaker = new MhtFileMaker();
$MhtFileMaker->SetFrom('foobar <foobar@mailinator.com>');
$MhtFileMaker->SetSubject( 'any subject' );
$MhtFileMaker->SetBaseDir( './cont/' );
$MhtFileMaker->SetFirstPage('index.htm');
$MhtFileMaker->AutoAddFiles();
$MhtFileMaker->MakeFile( './mht/cont.mht' );

この程度のコードで実現することができます

補足1

トップページから関連するファイルへのリンクは相対パスになっている必要があります
相対パスになっていないものはライブラリ側で面倒を見てくれません。

補足2

先に上げたURLに公開されているライブラリは
生成するmhtファイルと同等のメモリを消費してしまうため
巨大なmhtファイルが生成出来ないという問題があります

これはファイルポインタ周りをいじれば改善するので
メモリ節約パッチを当てたサンプルを張っておきます

mht.lib.php
<?php
/***********************************************************************
Class:    Mht File Maker
Version:   1.2 beta
Date:     02/11/2007
Author:    Wudi <wudicgi@yahoo.de>
Description: The class can make .mht file.
***********************************************************************/

/***********************************************************************
Date:        05/07/2014
Author:      zarchis
Description: Memory saving patch
***********************************************************************/

/***********************************************************************
::usage::

require_once 'mht.lib.php';

$MhtFileMaker = new MhtFileMaker();

$MhtFileMaker->SetFrom('Wudi <wudipro@yahoo.de>');
$MhtFileMaker->SetSubject('Example');

$MhtFileMaker->SetBaseDir('webpages');
$MhtFileMaker->SetFirstPage('index.htm');

$MhtFileMaker->AutoAddFiles();

$MhtFileMaker->MakeFile('example.mht');

echo '<a href="example.mht" target=_blank>Finished.</a>';

***********************************************************************/


class MhtFileMaker{
  var $config = array();
  var $headers = array();
  var $headers_exists = array();
  var $files = array();
  var $boundary;
  var $dir_base;
  var $page_first;

  function MhtFile($config = array()){

  }

  function SetHeader($header){
    $this->headers[] = $header;
    $key = strtolower(substr($header, 0, strpos($header, ':')));
    $this->headers_exists[$key] = TRUE;
  }

  function SetFrom($from){
    $this->SetHeader("From: $from");
  }

  function SetSubject($subject){
    $this->SetHeader("Subject: $subject");
  }

  function SetDate($date = NULL, $istimestamp = FALSE){
    if ($date == NULL) {
      $date = time();
    }
    if ($istimestamp == TRUE) {
      $date = date('D, d M Y H:i:s O', $date);
    }
    $this->SetHeader("Date: $date");
  }

  function SetBoundary($boundary = NULL){
    if ($boundary == NULL) {
      $this->boundary = '--' . strtoupper(md5(mt_rand())) . '_MULTIPART_MIXED';
    } else {
      $this->boundary = $boundary;
    }
  }

  function SetBaseDir($dir){
    $this->dir_base = str_replace("\\", "/", realpath($dir));
  }

  function SetFirstPage($filename){
    $this->page_first = str_replace("\\", "/", realpath("{$this->dir_base}/$filename"));
  }

  function AutoAddFiles(){
    if (!isset($this->page_first)) {
      exit ('Not set the first page.');
    }
    $filepath = str_replace($this->dir_base, '', $this->page_first);
    $filepath = 'http://mhtfile' . $filepath;
    $this->AddFile($this->page_first, $filepath, NULL);
    $this->AddDir($this->dir_base);
  }

  function AddDir($dir){
    $handle_dir = opendir($dir);
    while ($filename = readdir($handle_dir)) {
      if (($filename!='.') && ($filename!='..') && ("$dir/$filename"!=$this->page_first)) {
        if (is_dir("$dir/$filename")) {
          $this->AddDir("$dir/$filename");
        } elseif (is_file("$dir/$filename")) {
          $filepath = str_replace($this->dir_base, '', "$dir/$filename");
          $filepath = 'http://mhtfile' . $filepath;
          $this->AddFile("$dir/$filename", $filepath, NULL);
        }
      }
    }
    closedir($handle_dir);
  }

  function AddFile($filename, $filepath = NULL, $encoding = NULL){
    if ($filepath == NULL) {
      $filepath = $filename;
    }
    $mimetype = $this->GetMimeType($filename);
    $this->AddContents($filepath, $mimetype, $filename, $encoding);
  }

  function AddContents($filepath, $mimetype, $filename, $encoding = NULL){

    $this->files[] = array('filepath' => $filepath,
                'mimetype' => $mimetype,
                'filename' => $filename,
                'encoding' => $encoding);
  }

  function CheckHeaders(){
    if (!array_key_exists('date', $this->headers_exists)) {
      $this->SetDate(NULL, TRUE);
    }
    if ($this->boundary == NULL) {
      $this->SetBoundary();
    }
  }

  function CheckFiles(){
    if (count($this->files) == 0) {
      return FALSE;
    } else {
      return TRUE;
    }
  }

  function GetFile($fp){
    $this->CheckHeaders();
    if (!$this->CheckFiles()) {
      exit ('No file was added.');
    }
    $contents = implode("\r\n", $this->headers);
    $contents .= "\r\n";
    $contents .= "MIME-Version: 1.0\r\n";
    $contents .= "Content-Type: multipart/related;\r\n";
    $contents .= "\tboundary=\"{$this->boundary}\";\r\n";
    $contents .= "\ttype=\"" . $this->files[0]['mimetype'] . "\"\r\n";
    $contents .= "X-MimeOLE: Produced By Mht File Maker v1.0 beta\r\n";
    $contents .= "\r\n";
    $contents .= "This is a multi-part message in MIME format.\r\n";
    $contents .= "\r\n";
    
    fwrite($fp, $contents); $contents = "";
    
    foreach ($this->files as $file) {
      $filecont = file_get_contents($file['filename']);
      $encoding = $file['encoding'];
      if ($encoding == NULL) {
        $filecont = chunk_split(base64_encode($filecont), 76);
        $encoding = 'base64';
      }
    
      $contents .= "--{$this->boundary}\r\n";
      $contents .= "Content-Type: $file[mimetype]\r\n";
      $contents .= "Content-Transfer-Encoding: $encoding\r\n";
      $contents .= "Content-Location: $file[filepath]\r\n";
      $contents .= "\r\n";
      $contents .= $filecont;
      $contents .= "\r\n";
      
      fwrite($fp, $contents); $contents = "";
    }
    $contents .= "--{$this->boundary}--\r\n";
    
    fwrite($fp, $contents); $contents = "";
  }

  function MakeFile($filename){
    $fp = fopen($filename, 'w');
    $this->GetFile($fp);
    fclose($fp);
  }

  function GetMimeType($filename){
    $pathinfo = pathinfo($filename);
    switch ($pathinfo['extension']) {
      case 'htm': $mimetype = 'text/html'; break;
      case 'html': $mimetype = 'text/html'; break;
      case 'txt': $mimetype = 'text/plain'; break;
      case 'cgi': $mimetype = 'text/plain'; break;
      case 'php': $mimetype = 'text/plain'; break;
      case 'css': $mimetype = 'text/css'; break;
      case 'jpg': $mimetype = 'image/jpeg'; break;
      case 'jpeg': $mimetype = 'image/jpeg'; break;
      case 'jpe': $mimetype = 'image/jpeg'; break;
      case 'gif': $mimetype = 'image/gif'; break;
      case 'png': $mimetype = 'image/png'; break;
      default: $mimetype = 'application/octet-stream'; break;
    }
    return $mimetype;
  }
}
?>

補足3

補足2で巨大なmhtファイルを生成できるようになりましたが
ブラウザ側の都合でファイルサイズに制限があるのが実情です

100MB以上ならブラウザが非常に重くなり
300MB以上なら開くことが不可能になります

実用上は100MBが上限かなと感じています

5
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?