ケータイ端末からの画像の再配布を防止するには

By ookura - 08/10/17 - このエントリをはてなブックマークに追加このエントリをYahoo!ブックマークに追加このエントリをdel.icio.usに追加このエントリをFC2ブックマークに追加

前回は画像サイズの変更方法について説明しましたが、今回は画像の再配布防止処理について説明します。
→参照:「ケータイ端末別に画像画面サイズを変換するには」
 
 


画像の再配布とは

ケータイサイトでは端末にもよりますが、サイトから画像をダウンロードしたり外部に転送したりすることができます。
ダウンロードした画像の外部への転送方法には、メールに添付して転送、SDカード等のメモリ経由で転送、赤外線送信を利用した転送などがあります。
端末へのダウンロードに関しては全てを防ぎきることはできないですが、端末から外部への転送を防止することが可能です。
 
 


画像の再配布を防止するには

再配布を防止する方法は、キャリアによって異なります。
 
DoCoMo
画像バイナリのコメント部に「copy=”NO”」を記入します。
 
au
画像バイナリのコメント部に「kddi_copyright=on」を記入します。
 
Softbank
再配布のみを防止することはできませんが、画像出力時に以下のヘッダを出力することで端末への保存自体を防止することができます。

x-jphone-copyright: no-store, no-transfer, no-peripheral

※上記の方法は非パケット機種の一部端末では対応していません。
 
 


画像バイナリのコメント部とは

画像ファイルはバイナリデータです。
例えばJPEGファイルの場合、バイナリレベルではこのような構造になっています。

(前略) マーカ(FF) コメント部識別子(FE) コメントデータのバイト数+2(例:000B) コメントデータ マーカ(FF) (後略)

 
今回紹介するJPEG画像にコメントを入れる方法では、バイナリデータを変更してコメント部のコメントを上書きしています。
※コメント部の変更には上記の他にKDDI JPEGコンバータを使う方法やImageMagickの機能を使う方法もありますが、コンバータの場合は動的に処理できないですし、ImageMagickはサーバーへのインストールが必要になります。
※GIF画像及びPNG画像の場合も同様の方法で対応可能ですが、画像バイナリの形式が異なるためコメントの挿入方法が異なります。こちらに関しては別途説明予定です。
 
 


処理の手順

処理の手順は以下の通りです。
 
ユーザーエージェントからキャリアを判別する

ファイルを読み込み、画像IDを取得する

バッファ機能を有効にする(DoCoMo,auの場合)

JPEGヘッダを出力する

画像保存防止ヘッダを出力する(Softbankの場合)

画像データを出力する

出力したバッファデータを取得する(DoCoMo,auの場合)

コメントを埋め込む(DoCoMo,auの場合)

変更したバッファを出力する(DoCoMo,auの場合)

メモリを開放する
 
 


ユーザーエージェントの判別

キャリア毎に方法が異なるのでキャリアを判別しておきます。
漏れを防ぐためwillcom等その他のキャリアの場合は出力しないようにしています。
厳密にはキャリアのIPでチェックした方がよいです。

// ユーザーエージェント判別
$userAgent = $_SERVER['HTTP_USER_AGENT'];
if (preg_match('/^DoCoMo/', $userAgent)) {
    $carrier = 'DoCoMo';
} elseif (preg_match('/^(J\-PHONE|Vodafone|SoftBank|MOT\-)/', $userAgent)) {
    $carrier = 'SoftBank';
} elseif (preg_match('/^(KDDI\-|UP\.Browser)/', $userAgent)) {
    $carrier = 'au';
} else {
    echo 'Error : Out of allowed carrier.';
    exit;
}

 
 


バッファ機能を有効にする

DoCoMo,auの場合は出力した画像を再度変数に取り込む必要がありますので、ob_start関数でバッファを有効にします。
バッファを利用すると、標準出力に出力したデータを取り込むことができます。

// DoCoMo,auの場合は後処理でバッファ取得のためバッファ機能を有効化
if (in_array($carrier, array('DoCoMo', 'au'))) {
    // バッファ機能を有効化
    ob_start();
}

 
 


画像保存防止ヘッダを出力する

Softbankのみこのヘッダを出力することで保存を防止できます。

// ソフトバンクの場合は画像保存防止のヘッダを書き出す
if ($carrier === 'SoftBank') {
    // ソフトバンク向け画像保存防止処理
    header("x-jphone-copyright: no-transfer, no-peripheral");

}

以下のように保存は許可するが転送を防止する、という設定もあります。

x-jphone-copyright: no-transfer, no-peripheral

ですが、この場合、機種によってメール転送は不可だけどSDカードには転送できる、というような状態になりますので、保存自体を禁止した方がよいでしょう。
 
上記の方法が有効な端末は3GC端末に限られます。非パケット端末の場合は別の方法で対応する必要があります。
 
 


出力したバッファデータを取得する

DoCoMo,auの場合は出力した画像データを再度変数に取り込みます。
ob_get_clean関数を使うとバッファ取得後、標準出力を一旦クリアできます。

// DoCoMo,auの場合は画像バイナリに書き込み
if (in_array($carrier, array('DoCoMo', 'au'))) {
    // バッファデータの取得
    $buffer = ob_get_clean();
}

 
 


コメントの埋め込み

コメントをコメント部に上書きします。
DoCoMoの場合は「copy=”NO”」の文字列を追記するのでバイト数のデータは9+2=13→000B(16進)になります。
auの場合は「kddi_copyright=on」の文字列を追記するのでバイト数のデータは17+2=19→0013(16進)になります。
コメント部の場所はバイナリで判別します。

// バイナリのコメント部以外を抽出
$part1 = explode("\xFF\xFE", $buffer, 2);
$part2 = explode("\xFF", $part1[1], 2);

// コメント部を上書き
if ($carrier === 'DoCoMo') {
    // 000Bは「copy="NO"」の文字列バイト数(9) + 2 = 13 の16進数
    $buffer = $part1[0] . "\xFF\xFE\x00\x0Bcopy=\"NO\"\xFF" . $part2[1];
    
} elseif ($carrier === 'au') {
    // 0013は「kddi_copyright=on」の文字列バイト数(17) + 2 = 19 の16進数
    $buffer = $part1[0] . "\xFF\xFE\x00\x13kddi_copyright=on\xFF" . $part2[1];
    
}

バイナリは”\xFF”のような文字列で指定することができます。
バイナリに関する詳細な説明はここでは省略します。
 
 


変更したバッファの出力

バイナリデータをそのまま標準出力に書き出すと先にJPEGヘッダを出力しているので画像として表示されます。

// バッファ出力
print $buffer;

 
 


PHPソース例

実際のソースは以下の通りです。
 
sample1.php

<?php
/* 
 * 画像に再配布防止処理をつけて出力するサンプル
 */

// ユーザーエージェント判別
$userAgent = $_SERVER['HTTP_USER_AGENT'];
if (preg_match('/^DoCoMo/', $userAgent)) {
    $carrier = 'DoCoMo';
} elseif (preg_match('/^(J\-PHONE|Vodafone|SoftBank|MOT\-)/', $userAgent)) {
    $carrier = 'SoftBank';
} elseif (preg_match('/^(KDDI\-|UP\.Browser)/', $userAgent)) {
    $carrier = 'au';
} else {
    echo 'Error : Out of allowed carrier.';
    exit;
}

// ファイル名をクエリから取得
$imagePath = basename($_GET['file']);

// ファイルの存在チェック
if ((!file_exists($imagePath)) || ($imagePath == '')) {
    echo 'Error : File not exists.';
    exit;
}

// 転送防止処理追加出力

// 拡張子の取得
$pathinfo = pathinfo($imagePath);
if (empty($pathinfo['extension'])) {
    echo 'Error : Extention not exists in file name.';
    exit;
}

// 画像ファイルのmimetypeを確認
$imageInfo = getimagesize($imagePath);
$mimeType = image_type_to_mime_type($imageInfo[2]);

// 画像リサイズ
switch ($pathinfo['extension']) {
case "jpeg":
case "jpg":
    if ($mimeType !== 'image/jpeg') {
        echo 'Error : This file is not jpeg file.';
        exit;
    }
    $img_out = imagecreatefromjpeg($imagePath);
    break;
    
case "gif":
    if ($mimeType !== 'image/gif') {
        echo 'Error : This file is not gif file.';
        exit;
    }
    $img_out = imagecreatefromgif ($imagePath);
    break;
    
case "png":
    if ($mimeType !== 'image/png') {
        echo 'Error : This file is not png file.';
        exit;
    }
    $img_out = imagecreatefrompng ($imagePath);
    break;
    
default:
    echo 'Error : This file is not allowed file type.';
    exit;
    break;
}

// DoCoMo,auの場合は後処理でバッファ取得のためバッファ機能を有効化
if (in_array($carrier, array('DoCoMo', 'au'))) {
    // バッファ機能を有効化
    ob_start();
}

// JPEGヘッダ出力
header("Content-Type: image/jpeg");

// ソフトバンクの場合は画像保存防止のヘッダを書き出す
if ($carrier === 'SoftBank') {
    // ソフトバンク向け画像保存防止処理
    header("x-jphone-copyright: no-transfer, no-peripheral");

}

// 画像出力
imagejpeg($img_out);

// DoCoMo,auの場合は画像バイナリに書き込み
if (in_array($carrier, array('DoCoMo', 'au'))) {
    
    // バッファデータの取得
    $buffer = ob_get_clean();
    
    // バイナリのコメント部以外を抽出
    $part1 = explode("\xFF\xFE", $buffer, 2);
    $part2 = explode("\xFF", $part1[1], 2);
    
    // コメント部を上書き
    if ($carrier === 'DoCoMo') {
        // 000Bは「copy="NO"」の文字列バイト数(9) + 2 = 13 の16進数
        $buffer = $part1[0] . "\xFF\xFE\x00\x0Bcopy=\"NO\"\xFF" . $part2[1];
        
    } elseif ($carrier === 'au') {
        // 0013は「kddi_copyright=on」の文字列バイト数(17) + 2 = 19 の16進数
        $buffer = $part1[0] . "\xFF\xFE\x00\x13kddi_copyright=on\xFF" . $part2[1];
        
    }
    
    // バッファ出力
    print $buffer;
}

// メモリ解放
imagedestroy($img_out);
?>

 
 


実行例

実行例はこちらからご確認下さい。

URLをメールで送る
http://ookura.tanikaze.com/Sample/post784/
 
 


関連URL

再配布不可識別子 | サービス・機能 | NTTドコモ
http://www.nttdocomo.co.jp/service/imode/make/content/drm/redistribution/index.html
KDDI au: 技術情報 > GIF画像
http://au.kddi.com/ezfactory/tec/spec/gif.html
ソフトバンク技術情報 HTTP編(PDF)
http://www2.developers.softbankmobile.co.jp/dp/tool_dl/download.php?docid=119&companyid=
KDDI au- 技術情報 – JPEGコンバータ
http://www.au.kddi.com/ezfactory/tec/spec/jpeg.html
ke-tai.org – Blog Archive – 各キャリアの画像保存・転送制限の設定方法をまとめてみました
http://ke-tai.org/blog/2008/06/30/imgnoforward/
携帯画像の転送禁止 – 神奈川の田舎でIT(システム備忘録)
http://d.hatena.ne.jp/evolution6/20080827