【Perl講座 第4回】車輪の再発明を防ぐ!CPANモジュールの導入とCGI.pmによるファイルアップロード実装

「全部自分で書く」のは、今日で終わりにしよう。

こんにちは!「LINUX工房」管理人の「リナックス先生」です。
前回は、ファイルの読み書きやループ処理を駆使して、自力で掲示板システムを作り上げました。

しかし、プログラミングには「車輪の再発明(Reinventing the wheel)」という言葉があります。
「すでに誰かが作ってくれた優れた道具(車輪)があるのに、それを知らずにイチから自分で作り直すのは時間の無駄だ」という意味です。

コウ君

先生、前回の掲示板、作るの結構大変でした…。
データの区切り文字とか、改行の処理とか、もっと簡単にやる方法はないんですか?
あと、画像をアップロードしたいんですけど、これって自分でプログラム書くの無理じゃないですか?

リナックス先生

良いところに気がついたわね、コウ君。
特に「ファイルアップロード」や「メール送信」のような複雑な処理を、ゼロから書くのはプロでも避けるわ。
Perlには「CPAN(シーパン)」という、世界中のエンジニアが作ったプログラムの宝庫があるの。
これを使えば、複雑な機能もたった数行で実装できるわよ!

本記事では、Perlの最大の武器である「モジュール(ライブラリ)」の活用法を学びます。
AlmaLinux 9 での正しいインストール方法から、CGI開発の必須ツール CGI.pm の高度な使い方、そしてファイルアップロード機能の実装まで、実践的なテクニックを網羅します。

🐪 Perlサーバサイドプログラミング講座(バックナンバー)

現在地:【第4回】車輪の再発明を防ぐ!CPANモジュールの導入とCGI.pmの活用


第1章:CPANとは?Perlの最強武器を知る

Perlが長年愛され続けている理由の一つが、CPAN (Comprehensive Perl Archive Network) の存在です。

1. 巨大な部品倉庫

CPANは、世界中のPerlプログラマが作成した「モジュール(便利な機能のまとまり)」を集めた巨大なアーカイブです。
「日付計算がしたい」「Excelファイルを読み込みたい」「Twitterに投稿したい」「PDFを作りたい」…
やりたいことの99%は、すでに誰かがモジュールとして公開しています。

2. モジュールのメリット

  • 開発速度の向上: 自分で書くと1週間かかる機能が、モジュールを使えば10分で終わります。
  • 高い信頼性: 世界中のエンジニアが使い、バグ修正を行っているため、自分で書くコードより遥かに高品質です。
  • セキュリティ: 脆弱性が見つかってもすぐに修正版がリリースされます。

第2章:AlmaLinux 9 でのモジュールインストール作法

モジュールを使うには、まずサーバーにインストールする必要があります。
ここには「2つの流派」があり、サーバー管理者は注意が必要です。

流派1:OSのパッケージマネージャー (dnf/yum) を使う【推奨】

AlmaLinuxなどのRHEL系OSでは、主要なPerlモジュールはRPMパッケージとして提供されています。
システム標準のPerlを使う場合は、dnf でインストールするのが最も安全で、OSのアップデート管理と統合できるため推奨されます。

パッケージ名のルール:
モジュール名が CGI なら → perl-CGI
モジュール名が LWP::UserAgent なら → perl-libwww-perl (例外もあります)

# 例:CGIモジュールのインストール
sudo dnf install perl-CGI

# 例:DBIモジュールのインストール
sudo dnf install perl-DBI

流派2:cpan / cpanm コマンドを使う

OSのリポジトリにない最新のモジュールや、マイナーなモジュールを入れる場合に使います。
cpanm (App::cpanminus) というツールが現代の標準です。

# cpanm自体のインストール
sudo dnf install cpanminus

# モジュールのインストール
sudo cpanm Data::Dumper

⚠️ 管理者へのアドバイス
初心者のうちは、可能な限り dnf でインストールすることをお勧めします。
cpan コマンドで無造作にインストールすると、OSが管理しているファイルと競合したり、依存関係が複雑になってシステムが不安定になることがあるからです。


第3章:CGI.pm を使い倒す(オブジェクト指向スタイル)

第2回で少し触れた CGI.pm ですが、これは単にデータを受け取るだけのツールではありません。
Webアプリに必要な機能がすべて詰まっています。

1. オブジェクト指向スタイルでの記述

CGI.pm には「関数呼び出しスタイル」と「オブジェクト指向スタイル」がありますが、モダンなPerlでは後者を使います。

use CGI;
my $q = CGI->new; # CGIオブジェクトを作成(インスタンス化)

これ以降は、$q->メソッド名 という形で機能を呼び出します。

2. 主要なメソッド一覧

メソッド 機能 使用例
param フォームデータの取得 my $name = $q->param('user_name');
header HTTPヘッダーの出力 print $q->header(-charset => 'UTF-8');
upload ファイルハンドル取得 my $fh = $q->upload('file_field');
cookie クッキーの操作 my $cookie = $q->cookie(...);
escapeHTML XSS対策(文字実体参照化) my $safe_str = $q->escapeHTML($str);

第4章:【実践】ファイルアップロード機能の実装

手書きで作ると地獄を見る「ファイルアップロード」も、CGI.pm を使えば驚くほど簡単です。
画像ファイルをサーバーに保存するプログラムを作ってみましょう。

1. HTMLフォームの作成 (upload.html)

ファイルを送る場合、form タグに enctype="multipart/form-data" が必須です。
これを忘れるとファイルの中身が送信されません。

<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>File Upload</title></head>
<body>
    <h1>画像アップロード</h1>
    <form action="/cgi-bin/upload.cgi" method="POST" enctype="multipart/form-data">
        画像を選択: <input type="file" name="photo"><br>
        <input type="submit" value="アップロード">
    </form>
</body>
</html>

2. 受信プログラムの作成 (upload.cgi)

sudo nano /var/www/cgi-bin/upload.cgi

以下のコードを記述します。

#!/usr/bin/perl

use strict;
use warnings;
use CGI;
use File::Basename; # ファイル名を取り出すモジュール

# アップロード先ディレクトリ(権限設定が必要!)
my $upload_dir = "/var/www/html/uploads";

my $q = CGI->new;
print $q->header(-charset => 'UTF-8');

# ファイル名を取得(クライアント側のパスが含まれる場合があるので処理する)
my $filename = $q->param('photo');

# ファイルハンドルを取得(これが中身)
my $fh = $q->upload('photo');

print "<html><body>";

if ($filename && $fh) {
    # 安全なファイル名のみ抽出(ディレクトリトラバーサル対策)
    my $safe_filename = basename($filename);
    
    # 保存先のフルパス
    my $output_file = "$upload_dir/$safe_filename";
    
    # 保存処理
    # バイナリモードで開き、バッファ経由で書き込む
    if (open(my $out, ">", $output_file)) {
        binmode $out; # 重要:画像などはバイナリモードにする
        while (my $bytesread = read($fh, my $buffer, 1024)) {
            print $out $buffer;
        }
        close($out);
        
        print "<h2>アップロード成功</h2>";
        print "<p>ファイル名: $safe_filename</p>";
        print "<img src='/uploads/$safe_filename' width='300'>";
    } else {
        print "<h2>保存エラー</h2>";
        print "<p>$!</p>";
    }
} else {
    print "<p>ファイルが選択されていません。</p>";
}

print "</body></html>";

3. 保存先ディレクトリの作成と権限設定

CGIがファイルを書き込めるように、保存先ディレクトリを作成して権限を与えます。

# ディレクトリ作成
sudo mkdir -p /var/www/html/uploads

# 権限設定(誰でも書き込める設定:本番ではApacheユーザーに限定すべき)
sudo chmod 777 /var/www/html/uploads

# SELinux設定(書き込み許可ラベルを付与)
sudo chcon -t httpd_sys_rw_content_t /var/www/html/uploads

4. 動作確認

ブラウザで upload.html にアクセスし、画像をアップロードしてみてください。
成功すれば、アップロードした画像が表示されるはずです。
これを自力で実装しようとすると、HTTPリクエストの生データ(multipart/form-data)を解析するだけで数百行のコードが必要になります。モジュールの偉大さがわかりますね。


第5章:デバッグの神「Data::Dumper」

開発が進むと、「変な動きをするけど、変数の中身がどうなっているか分からない!」という状況に陥ります。
そんな時、変数の中身(配列やハッシュの複雑な構造)をそのままテキストにして表示してくれるのが Data::Dumper です。

使い方

use Data::Dumper;

my %user = (
    name => "田中",
    skills => ["Perl", "Linux", "MySQL"],
    age => 30
);

# 中身を覗き見る
print STDERR Dumper(\%user);

このように print STDERR と組み合わせることで、Webブラウザの画面を壊さずに、Apacheのエラーログ(/var/log/httpd/error_log)に変数の内容を出力できます。
開発中は手放せないツールです。


第6章:外部サイトと連携する「LWP」

自分のサーバーの中だけで完結するのではなく、Yahoo!ニュースの情報を取ってきたり、Slackに通知を送ったりしたい。
そんな「Webブラウザの代わり」をしてくれるモジュールが LWP::UserAgent(通称 LWP)です。

インストール

sudo dnf install perl-libwww-perl

使用例:Webページの内容を取得する

use LWP::UserAgent;

my $ua = LWP::UserAgent->new;
my $response = $ua->get('https://www.google.com/');

if ($response->is_success) {
    print "Content-Type: text/plain\n\n";
    print $response->decoded_content; # 取得したHTMLを表示
} else {
    die $response->status_line;
}

これを使えば、天気予報APIを叩いて自サイトに表示する、といったマッシュアップも簡単に実現できます。


第7章:マニュアルの読み方(perldoc)

モジュールの使い方が分からない時、ネットで検索するのも良いですが、Perlには強力なマニュアル閲覧コマンド perldoc が付属しています。

# CGIモジュールのマニュアルを見る
perldoc CGI

# LWPのマニュアルを見る
perldoc LWP::UserAgent

英語ですが、一次情報(公式ドキュメント)がいつでも手元にあるのは大きな強みです。
q キーで終了できます。


まとめ:モジュールは「巨人の肩」

お疲れ様でした!
モジュールを使うことで、できることの幅が一気に広がりましたね。

今回の重要ポイント:

  • CPANはPerlの宝庫。やりたいことは大抵モジュールがある。
  • AlmaLinuxでは dnf install perl-モジュール名 を優先する。
  • CGI.pm を使えばファイルアップロードも簡単。
  • Data::Dumper でデバッグ効率を上げる。

さて、ファイル操作でのデータ保存には限界があります。
データ量が増えると検索が遅くなり、複雑な条件での抽出も困難です。
Webシステムの中心にあるのは、やはり「データベース(RDBMS)」です。

次回、第5回は「データはデータベースへ!MariaDB(MySQL)連携とDBI/DBDモジュール」です。
Linux標準のDBであるMariaDBを構築し、PerlからSQLを発行してデータを操作する方法を学びます。
ここからがいよいよ本格的なバックエンド開発です。お楽しみに!

▼ エンジニアとしてのキャリアを加速させる ▼

ファイルアップロードを試す
「VPS」で自分専用環境

おすすめVPSを見る

サーバーサイド技術を年収に
「ITエンジニア転職」

転職エージェントを見る

コメント