PowerCMS X ブログ

2025-06-09

動画に管理画面の権限や会員ログインによるアクセス制限をかける

PowerCMS ver.4.0で「VideoCaptions」が大幅に機能強化され、AI字幕作成や簡易動画編集などの機能が追加されました。
ストリーミング形式(HLS)への変換などもサポートされており、PowerCMS Xは動画 CMSとしても利用できるようになりました。

動画サイトの運営に関するリクエストに「編集中の動画に対する閲覧制限をしたい」「動画が外部に漏洩しないようにしたい」といったものがあります。
動画に閲覧制限をかける方法をいくつかご紹介します。

  • /media/ディレクトリに動画をアップロードして、その動画に閲覧制限をかける方法をご紹介します。
  • 動画のアップロードは FileUploaderプラグインを有効化してモデル「ファイル」のオブジェクトとしてアップロードする前提です。
  • また、ステータスによる閲覧制限をかけるため、ファイルオブジェクトには statusカラムを追加して有効期限対応を指定しておきます。

会員ログインによる閲覧制限

プラグイン「Members」による会員限定サイトを運営していることを前提とします。

/media/.htaccess

Require all denied
ErrorDocument 403 /viewer.php

まず、/media/ディレクトリへのアクセスを制限します。特定の拡張子のファイルを対象にしても良いですが、ここでは全てのファイルに対して制限をかけます。ErrorDocument 403 /viewer.php を指定して、リクエストを PHPへ渡すようにします。

/viewer.php

<?php
$base_path = '/opt/homebrew/var/www/powercmsx/'; // PowerCMS Xのディレクトリ
require_once( $base_path.'class.Prototype.php' );
$app = new Prototype();
$app->init();
$bootstrapper = new PTViewer();
if (!isset( $_SERVER['REDIRECT_URL'] ) ) {
    // /viewer.phpへ直接アクセスがあった時
    $bootstrapper->page_not_found( $app );
}
$redirect_url = $_SERVER['REDIRECT_URL'];
$dirname = dirname( $redirect_url );
$dir_name = '/' . $app->sanitize_dir( $dirname );
$file_name = basename( $redirect_url );
$file_name = $app->sanitize_file( $file_name );
$file_path = $app->document_root . $dir_name . $file_name;
if (! file_exists( $file_path ) ) {
    // ファイルが存在しない
    $bootstrapper->page_not_found( $app );
}
$obj = $app->db->model( 'upload_file' )->get_by_key( ['file_path' => $file_path ] );
if (! $obj->id ) {
    // ファイルオブジェクトが存在しない
    $bootstrapper->page_not_found( $app );
}
// 例えばファイルオブジェクトに statusカラムを追加している時
if ( $obj->status != 4 ) {
    // ステータスが公開でない時
    $bootstrapper->page_not_found( $app );
}
$member = $app->user( 'member' );
if (! $member ) {
    // 会員サイトのログインチェック
    $bootstrapper->page_not_found( $app, $obj->workspace, $app->translate( 'Permission denied.' ) );
}
// 必要に応じてメンバーの属性などをチェック
header( 'HTTP/1.1 200 OK' ); // 403ヘッダーを上書きする
$mime_type = $obj->mime_type;
header( "Content-Type: {$mime_type}" );
readfile( $file_path ); // ファイル出力
exit();

$bootstrapper->page_not_found( $app ); の結果はダイナミック・パブリッシュングのエラー表示となります。

ページが見つかりません(404ページ)

改良 : readfile関数の利用を避ける

readfileや echo file_get_contents( file_path );でも動画をブラウザへ返すことはできますが、
PHPを介して動画レスポンスを返していると大きなファイルサイズの動画へのリクエストが集中したりするとサーバーの負荷が一気に上がってしまいます。

そこで、mod_xsendfile を利用して、レスポンスはウェブサーバー(Apache)に任せてしまい、PHPでは権限のチェックのみを行うことにします。
mod_xsendfile.soをビルドしてサーバーに設置、httpd.confを編集します(編集後 httpdを再起動)。

httpd.conf

LoadModule xsendfile_module lib/httpd/modules/mod_xsendfile.so
<Directory "/var/www">
    XSendFile On
    XSendFilePath "/var/www"
</Directory>

/viewer.php

以下の部分を修正します。

header( 'HTTP/1.1 200 OK' ); // 403ヘッダーを上書きする
$mime_type = $obj->mime_type;
header( "Content-Type: {$mime_type}" );
readfile( $file_path ); // ファイル出力
exit();

ここを以下のように変更します。readfileを使わないため PHPでは権限のチェックのみを行うことで負荷を下げることができます。

header( 'HTTP/1.1 200 OK' ); // 403ヘッダーを上書きする
$mime_type = $obj->mime_type;
header( "Content-Type: {$mime_type}" );
header( "Content-Disposition: inline; filename=\"{$file_name}\"" );
header( "X-Sendfile: {$file_path}" ); // Apacheによるファイル出力
exit();

管理画面のユーザー権限による動画へのアクセス制限

会員ではなく、管理画面へのログイン状況とそのファイルオブジェクトの編集権限によって制限をかける方法です。

<?php
$base_path = '/var/www/powercmsx/'; // PowerCMS Xのディレクトリ
require_once( $base_path.'class.Prototype.php' );
$app = new Prototype();
$app->init();
$bootstrapper = new PTViewer();
if (!isset( $_SERVER['REDIRECT_URL'] ) ) {
    // /viewer.phpへ直接アクセスがあった時
    $bootstrapper->page_not_found( $app );
}
$redirect_url = $_SERVER['REDIRECT_URL'];
$dirname = dirname( $redirect_url );
$dir_name = '/' . $app->sanitize_dir( $dirname );
$file_name = basename( $redirect_url );
$file_name = $app->sanitize_file( $file_name );
$file_path = $app->document_root . $dir_name . $file_name;
if (! file_exists( $file_path ) ) {
    // ファイルが存在しない
    $bootstrapper->page_not_found( $app );
}
$obj = $app->db->model( 'upload_file' )->get_by_key( ['file_path' => $file_path ] );
if (! $obj->id ) {
    // ファイルオブジェクトが存在しない
    $bootstrapper->page_not_found( $app );
}
$user = $app->user();
if (! $user ) {
    // 管理画面にログインしていない
    $bootstrapper->page_not_found( $app, $obj->workspace, $app->translate( 'Permission denied.' ) );
}
if ( $obj->status != 4 ) {
    // ステータスが公開でない時
    $can_do = $app->can_do( 'upload_file', 'edit', $obj );
    if (! $can_do ) {
        // 編集権限がない
        $app->error( 'Permission denied.' );
    }
}
header( 'HTTP/1.1 200 OK' );
$mime_type = $obj->mime_type;
header( "Content-Type: {$mime_type}" );
header( "Content-Disposition: inline; filename=\"{$file_name}\"" );
header( "X-Sendfile: {$file_path}" );
exit();

$app->error( 'Permission denied.' ); の結果は、管理画面の権限エラーメッセージとなります。

管理画面の権限エラー画面

カテゴリー:技術情報 | サイト制作全般 | よくあるご質問 | コラム・その他

投稿者:Junnama Noda

ブログ内検索

アーカイブ


日本語
ふりがな付き
English
简体中文
繁體中文
한국어