首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 生成 CHM 帮助文檔:hhp/hhc/hhk 三文件自動構建與 HHC 編譯全流程

     編輯:PHP 綜合知識

CHM 文件結構

項目目錄/
├── index.html          # 內容頁面
├── chapter1/
│   ├── section1.html
│   └── section2.html
├── images/
│   └── logo.png
└── 生成文件/
    ├── project.hhp     # 項目配置
    ├── project.hhc     # 目錄結構 (TOC)
    └── project.hhk     # 關鍵字索引

核心類實現

<?php
declare(strict_types=1);

class ChmBuilder
{
    private string $srcDir;
    private string $outDir;
    private string $chmName;
    private string $title;
    private string $firstPage;
    private array $excludeDirs = ['.git', '.svn', 'node_modules', 'vendor'];
    private array $excludeFiles = ['.DS_Store', 'Thumbs.db'];
    private array $imageTypes = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'svg'];

    public function __construct(
        string $srcDir,
        string $outDir = '',
        string $chmName = 'manual',
        string $title = 'Documentation',
        string $firstPage = 'index.html'
    ) {
        $this->srcDir = rtrim($srcDir, '/\\');
        $this->outDir = $outDir ?: $this->srcDir;
        $this->chmName = $chmName;
        $this->title = $title;
        $this->firstPage = $firstPage;
    }

    public function build(): bool
    {
        $this->buildHhp();
        $this->buildHhc();
        $this->buildHhk();
        return $this->compile();
    }

    /** 1. 構建 .hhp 項目文件 */
    private function buildHhp(): void
    {
        $files = $this->scanFiles($this->srcDir);
        $fileList = implode("\n", $files);

        $content = <<outDir}/{$this->chmName}.chm
Contents file={$this->chmName}.hhc
Index file={$this->chmName}.hhk
Default topic={$this->firstPage}
Display compile progress=No
Full-text search=Yes
Language=0x804
Title={$this->title}
ImageType=Folder

[FILES]
{$fileList}
EOF;

        file_put_contents("{$this->outDir}/{$this->chmName}.hhp", $content);
    }

    /** 2. 構建 .hhc 目錄結構 */
    private function buildHhc(): void
    {
        $tree = $this->buildDirTree($this->srcDir);
        $tocItems = $this->renderToc($tree);
        
        $content = <<









    {$tocItems}
EOF; file_put_contents("{$this->outDir}/{$this->chmName}.hhc", $content); } /** 3. 構建 .hhk 關鍵字索引 */ private function buildHhk(): void { $files = $this->scanFiles($this->srcDir); $indexItems = []; foreach ($files as $file) { if (preg_match('/\.html?$/i', $file)) { $title = basename($file, '.html'); $title = basename($title, '.htm'); $indexItems[] = << ITEM; } } $content = <<
    EOF; $content .= implode("\n", $indexItems); $content .= "\n
"; file_put_contents("{$this->outDir}/{$this->chmName}.hhk", $content); } /** 調用 hhc.exe 編譯 */ private function compile(): bool { $hhpPath = "{$this->outDir}/{$this->chmName}.hhp"; if (!file_exists($hhpPath)) return false; // Windows 環境下 hhc.exe 通常在 "C:\Program Files (x86)\HTML Help Workshop\hhc.exe" $hhcExe = $this->findHhcExe(); if (!$hhcExe) { trigger_error('未找到 hhc.exe,請安裝 HTML Help Workshop', E_USER_WARNING); return false; } $cmd = '"' . $hhcExe . '" "' . $hhpPath . '"'; $output = []; $returnVar = 0; exec($cmd, $output, $returnVar); return $returnVar === 0 && file_exists("{$this->outDir}/{$this->chmName}.chm"); } private function findHhcExe(): ?string { $paths = [ 'C:\Program Files (x86)\HTML Help Workshop\hhc.exe', 'C:\Program Files\HTML Help Workshop\hhc.exe', getenv('ProgramFiles(x86)') . '\HTML Help Workshop\hhc.exe', ]; foreach ($paths as $p) { if (file_exists($p)) return $p; } return null; } /** 掃描所有 HTML/圖片文件 */ private function scanFiles(string $dir): array { $files = []; $iterator = new RecursiveIteratorIterator( new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS) ); foreach ($iterator as $file) { if ($file->isFile()) { $relPath = str_replace('\\', '/', substr($file->getPathname(), strlen($this->srcDir) + 1)); $ext = strtolower($file->getExtension()); if ($ext === 'html' || $ext === 'htm' || in_array($ext, $this->imageTypes)) { if (!$this->isExcluded($relPath)) { $files[] = $relPath; } } } } sort($files, SORT_NATURAL | SORT_FLAG_CASE); return $files; } /** 構建目錄樹 */ private function buildDirTree(string $dir): array { $tree = []; $iterator = new RecursiveIteratorIterator( new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS), RecursiveIteratorIterator::SELF_FIRST ); foreach ($iterator as $file) { $relPath = str_replace('\\', '/', substr($file->getPathname(), strlen($this->srcDir) + 1)); if ($this->isExcluded($relPath)) continue; $parts = explode('/', $relPath); $node = &$tree; foreach ($parts as $i => $part) { $isFile = $file->isFile() && $i === count($parts) - 1; $key = $isFile ? 'files' : 'dirs'; if (!isset($node[$key][$part])) { $node[$key][$part] = $isFile ? $relPath : ['dirs' => [], 'files' => []]; } $node = &$node[$key][$part]; } } return $tree; } private function renderToc(array $tree, int $depth = 0): string { $html = ''; $indent = str_repeat(' ', $depth); // 目錄 foreach ($tree['dirs'] ?? [] as $name => $subTree) { $html .= "{$indent}
  • \n"; $html .= "{$indent} \n"; $html .= "{$indent} \n"; $html .= "{$indent} \n"; $html .= "{$indent} \n"; $html .= "{$indent}
      \n"; $html .= $this->renderToc($subTree, $depth + 2); $html .= "{$indent}
    \n"; $html .= "{$indent}
  • \n"; } // 文件 foreach ($tree['files'] ?? [] as $name => $path) { $title = basename($name, '.html'); $title = basename($title, '.htm'); $html .= "{$indent}
  • \n"; $html .= "{$indent} \n"; $html .= "{$indent} \n"; $html .= "{$indent} \n"; $html .= "{$indent}
  • \n"; } return $html; } private function isExcluded(string $relPath): bool { foreach ($this->excludeDirs as $d) { if (strpos($relPath, $d . '/') === 0) return true; } foreach ($this->excludeFiles as $f) { if (basename($relPath) === $f) return true; } return false; } } ?>

    使用示例

    <?php
    require 'ChmBuilder.php';
    
    $builder = new ChmBuilder(
        srcDir: __DIR__ . '/docs',      // 包含 HTML 文檔的目錄
        outDir: __DIR__ . '/output',    // 輸出目錄
        chmName: 'my_manual',           // 生成 my_manual.chm
        title: '我的項目文檔',
        firstPage: 'index.html'
    );
    
    if ($builder->build()) {
        echo "CHM 生成成功: {$builder->outDir}/{$builder->chmName}.chm\n";
    } else {
        echo "生成失敗,請檢查 hhc.exe 是否安裝\n";
    }
    ?>

    前置條件與注意事項

    要求說明
    Windows 環境CHM 編譯器 hhc.exe 僅運行於 Windows
    HTML Help Workshop微軟官方工具,必須安裝 下載地址
    文檔編碼源 HTML 建議 UTF-8,hhc.exe 會自動處理
    路徑長度Windows 260 字符限制,目錄不要太深

    現代化替代方案

    • MkDocs + mkdocs-chm:Markdown 源碼 → HTML → CHM
    • DocFX:.NET 生態,支持輸出 CHM/PDF/Web
    • GitBook / VuePress / VitePress:輸出現代化 Web 文檔站點,響應式、可搜索、版本控制
    • Electron + HTML:打包為跨平台桌面應用

    CHM 格式雖老但仍在企業內部文檔、離線幫助系統中廣泛使用,PHP 自動化構建能大幅提升文檔發布效率。

    1. 上一篇文章:
    2. 下一篇文章:
    Copyright © 程式碼之家 All Rights Reserved