Help us understand the problem. What is going on with this article?

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

More than 5 years have passed since last update.

概要

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が上限かなと感じています

zarchis
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした