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

PHP 解析 SWF 檔案:取得寬高、幀率、背景色、版本資訊

     編輯:PHP 綜合知識

SWF 檔案結構簡述

SWF (Small Web Format) 以 Header 開頭:

  • 前 3 字節:FWS (未壓縮) 或 CWS (Zlib 壓縮)
  • 第 4 字節:版本號
  • 第 5-8 字節:檔案長度(小端序)
  • 接著為 RECT 結構:Nbits (5 bits) + Xmin, Xmax, Ymin, Ymax (各 Nbits) → 畫面尺寸(單位:twips, 1/20 像素)
  • 接著為 FrameRate (Fixed8, 2 字節) 與 FrameCount (UI16, 2 字節)

完整解析類

<?php
class SwfInfoParser
{
    public function parse(string $filePath): ?array
    {
        if (!file_exists($filePath)) return null;

        $data = file_get_contents($filePath);
        if (strlen($data) < 8) return null;

        $signature = substr($data, 0, 3);
        $compressed = ($signature === 'CWS');
        $version = ord($data[3]);
        $fileLength = unpack('V', substr($data, 4, 4))[1];

        // 解壓縮(若為 CWS)
        if ($compressed) {
            $data = substr($data, 0, 8) . gzuncompress(substr($data, 8));
        }

        // 解析 RECT (畫面尺寸)
        $pos = 8;
        $bits = $this->readBits($data, $pos, 5); // Nbits
        $pos += 5;
        $xmin = $this->readSBits($data, $pos, $bits); $pos += $bits;
        $xmax = $this->readSBits($data, $pos, $bits); $pos += $bits;
        $ymin = $this->readSBits($data, $pos, $bits); $pos += $bits;
        $ymax = $this->readSBits($data, $pos, $bits); $pos += $bits;

        $widthTwips = $xmax - $xmin;
        $heightTwips = $ymax - $ymin;
        $width = $widthTwips / 20;
        $height = $heightTwips / 20;

        // FrameRate (Fixed8: 8.8 定點數)
        $frameRateRaw = unpack('n', substr($data, $pos, 2))[1];
        $frameRate = $frameRateRaw / 256;
        $pos += 2;

        // FrameCount (UI16)
        $frameCount = unpack('v', substr($data, $pos, 2))[1];

        // 背景色:SWF 標準 Header 無背景色,需解析第一個 Tag (SetBackgroundColor, tag code 9)
        $bgColor = $this->parseBackgroundColor($data, $pos);

        return [
            'version' => $version,
            'compressed' => $compressed,
            'file_length' => $fileLength,
            'width' => $width,
            'height' => $height,
            'frame_rate' => $frameRate,
            'frame_count' => $frameCount,
            'background_color' => $bgColor, // 格式 #RRGGBB 或 null
        ];
    }

    private function readBits(string &$data, int &$pos, int $count): int
    {
        $val = 0;
        for ($i = 0; $i < $count; $i++) {
            $bytePos = $pos >> 3;
            $bitPos = 7 - ($pos & 7);
            $val = ($val << 1) | (($data[$bytePos] >> $bitPos) & 1);
            $pos++;
        }
        return $val;
    }

    private function readSBits(string &$data, int &$pos, int $count): int
    {
        $val = $this->readBits($data, $pos, $count);
        // 有號數擴展
        if ($val & (1 << ($count - 1))) {
            $val -= (1 << $count);
        }
        return $val;
    }

    private function parseBackgroundColor(string $data, int $startPos): ?string
    {
        // 簡易掃描 Tag 9 (SetBackgroundColor)
        $pos = $startPos;
        $len = strlen($data);
        while ($pos + 2 < $len) {
            $tagHeader = unpack('n', substr($data, $pos, 2))[1];
            $tagCode = $tagHeader >> 6;
            $tagLength = $tagHeader & 0x3F;
            $pos += 2;
            if ($tagLength === 0x3F) { // 長格式
                if ($pos + 4 > $len) break;
                $tagLength = unpack('V', substr($data, $pos, 4))[1];
                $pos += 4;
            }
            if ($tagCode === 9 && $tagLength >= 3) { // SetBackgroundColor
                $rgb = unpack('C3', substr($data, $pos, 3));
                return sprintf('#%02X%02X%02X', $rgb[1], $rgb[2], $rgb[3]);
            }
            $pos += $tagLength;
        }
        return null;
    }
}

使用範例

<?php
$parser = new SwfInfoParser();
$info = $parser->parse('demo.swf');
if ($info) {
    echo "版本:{$info['version']}\n";
    echo "尺寸:{$info['width']} x {$info['height']} px\n";
    echo "幀率:{$info['frame_rate']} fps\n";
    echo "總幀數:{$info['frame_count']}\n";
    echo "背景色:{$info['background_color'] ?? '無'}\n";
} else {
    echo "解析失敗或檔案不存在";
}

注意事項

  • 壓縮 SWF (CWS):必須先 gzuncompress() 解壓尾部資料,再解析結構。
  • 位元組序:SWF 多為小端序,使用 unpack('v'/'V')。
  • RECT 位元組對齊:Nbits 後的四個座標值緊湊排列,需逐位讀取(上方 readBits 實現)。
  • 背景色:不在 Header,需掃描 Tag 9;若 SWF 未包含該 Tag 則無背景色。
  • ActionScript 3 / 新版 SWF:結構相同,但可能包含更多 Tag,解析邏輯通用。

替代方案

  • getID3():強大的媒體檔案分析庫,支援 SWF 詳盡資訊提取。composer require james-heinrich/getid3
  • swftools (swfdump):命令列工具,可 exec('swfdump -d file.swf') 取得結構化輸出。

總結

SWF 格式規格公開且結構固定,PHP 純代碼即可完整解析 Header 與關鍵 Tag。上方 SwfInfoParser 類提供輕量、無依賴的解決方案,適合嵌入上傳驗證、預覽生成等場景。

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