內容

名稱

perlfaq9 - 網路、電子郵件和網路

版本

版本 5.20210520

說明

本節討論與執行網站、傳送和接收電子郵件以及一般網路相關的問題。

我應該使用網頁架構嗎?

是的。如果您要建立具有任何程度互動性(表單/使用者/資料庫)的網站,您會想要使用架構,以簡化處理要求和回應。

如果沒有互動性,您可能還是會想要考慮使用類似 Template ToolkitPlack::Middleware::TemplateToolkit 的東西,這樣維護您的 HTML 檔案(和其他資產)會更容易。

我應該使用哪個網頁架構?

這個問題沒有簡單的答案。Perl 架構可以執行從基本檔案伺服器和小型內部網路到大型跨國多語言網站,這些網站是國際企業的核心。

以下是幾個架構的清單,其中附有註解,可能會根據您的特定需求幫助您做出決定。請先閱讀文件,然後在相關的郵寄清單或 IRC 頻道上提出問題。

Catalyst

強烈的物件導向和功能齊全,具有悠久的開發歷史,以及龐大的社群和附加元件生態系統。它非常適合大型且複雜的應用程式,您可以在其中完全控制伺服器。

Dancer2

沒有舊包袱,提供輕量且易於學習的 API。具有不斷擴充的附加元件生態系統。它最適合較小的專案,而且初學者很容易學習。

Mojolicious

獨立且功能強大,適用於小型和大型專案,重點在於 HTML5 和 WebSocket 等即時網路技術。

Web::Simple

強烈的物件導向且精簡,為速度而建,並作為建立微型網路應用程式、自訂架構或將現有的相容於 Plack 的網路應用程式與一個中央調度器結合在一起的工具包。

所有這些都會與 Plack 互動或使用它,在 Perl 中建立網站時,了解它的基礎知識是值得的(有很多有用的 Plack::Middleware)。

Plack 和 PSGI 是什麼?

PSGI 是 Perl 網路伺服器閘道介面規格,它是許多 Perl 網路架構使用的標準,您不需要了解它來建立網站,您可能想要使用的部分是 Plack

Plack 是一組用於使用 PSGI 堆疊的工具。它包含 中間件 元件、參考伺服器和網路應用程式架構的公用程式。Plack 類似於 Ruby 的 Rack 或 Python 的 Paste for WSGI。

你可以使用 Plack 和你自己的程式碼建立一個網站,但對於任何非非常基本的網站,使用一個網路架構(使用 https://plackperl.org)會是一個更好的選擇。

如何從字串中移除 HTML?

使用 HTML::StripHTML::FormatText,它不僅移除 HTML,還會嘗試對產生的純文字進行一些簡單的格式化。

如何萃取網址?

HTML::SimpleLinkExtor 會從 HTML 中萃取網址,它處理錨點、圖片、物件、框架和許多其他可能包含網址的標籤。如果你需要更複雜的功能,你可以建立 HTML::LinkExtorHTML::Parser 的子類別。你甚至可以使用 HTML::SimpleLinkExtor 作為範例,建立專門符合你需求的功能。

你可以使用 URI::FindURL::Search 從任意文字文件中萃取網址。

如何擷取 HTML 檔案?

(由 brian d foy 提供)

核心 HTTP::Tiny 模組可以擷取網路資源,並將其內容作為字串傳回給你

use HTTP::Tiny;

my $ua = HTTP::Tiny->new;
my $html = $ua->get( "http://www.example.com/index.html" )->{content};

它也可以將資源直接儲存在檔案中

$ua->mirror( "http://www.example.com/index.html", "foo.html" );

如果你需要執行更複雜的任務,HTTP::Tiny 物件可以透過設定屬性進行自訂,或者你可以使用 libwww-perl 套件中的 LWP::UserAgent 或 Mojolicious 套件中的 Mojo::UserAgent,讓常見任務更容易執行。如果你想要模擬互動式網路瀏覽器,你可以使用 WWW::Mechanize 模組。

如何自動化 HTML 表單提交?

如果你正在執行複雜的任務,例如瀏覽許多頁面和表單或網站,你可以使用 WWW::Mechanize。請參閱其文件以取得所有詳細資訊。

如果你使用 GET 方法提交值,請建立一個網址,並使用 HTTP::Tiny 中的 www_form_urlencode 方法對表單進行編碼

use HTTP::Tiny;

my $ua = HTTP::Tiny->new;

my $query = $ua->www_form_urlencode([ q => 'DB_File', lucky => 1 ]);
my $url = "https://metacpan.org/search?$query";
my $content = $ua->get($url)->{content};

如果你使用 POST 方法,post_form 方法會適當地對內容進行編碼。

use HTTP::Tiny;

my $ua = HTTP::Tiny->new;

my $url = 'https://metacpan.org/search';
my $form = [ q => 'DB_File', lucky => 1 ];
my $content = $ua->post_form($url, $form)->{content};

如何在網路上解碼或建立那些 %-編碼?

大多數情況下,您不需要這麼做,因為您的網頁架構,或者如果您正在提出要求,LWP 或其他模組會為您處理。

要自行編碼字串,請使用 URI::Escape 模組。uri_escape 函式會傳回已編碼的字串

my $original = "Colon : Hash # Percent %";

my $escaped = uri_escape( $original );

print "$escaped\n"; # 'Colon%20%3A%20Hash%20%23%20Percent%20%25'

要解碼字串,請使用 uri_unescape 函式

my $unescaped = uri_unescape( $escaped );

print $unescaped; # back to original

請記住,不要編碼完整的 URI,您需要分別跳脫每個元件,然後再將它們串接在一起。

如何重新導向至其他頁面?

大多數 Perl 網頁架構將有執行此操作的機制,使用 Catalyst 架構會是

$c->res->redirect($url);
$c->detach();

如果您使用 Plack(大多數架構都使用),那麼如果您從 Apache 遷移或有您想要始終重新導向的 URL,那麼 Plack::Middleware::Rewrite 值得一看。

如何為我的網頁設定密碼?

請查看您正在使用的網頁架構是否有驗證系統,以及是否符合您的需求。

或者查看 Plack::Middleware::Auth::Basic 或其他 Plack 驗證 選項。

如何確保使用者無法輸入導致我的 CGI 腳本執行不良動作的表單值?

(由 brian d foy 提供)

您無法阻止人們向您的腳本傳送不良資料。即使您新增一些用戶端檢查,人們也可能會停用它們或完全繞過它們。例如,有人可能會使用 LWP 等模組提交到您的網站。如果您想防止嘗試使用 SQL 注入或其他類型的攻擊的資料(而且您應該想這麼做),您必須不信任輸入程式的所有資料。

perlsec 文件包含有關資料安全的一般建議。如果您使用 DBI 模組,請使用佔位符填入資料。如果您使用 systemexec 執行外部程式,請使用清單格式。還有許多其他預防措施您應該採取,這裡列舉不完,而且它們大多屬於不使用您無意使用的任何資料的範疇。不要相信任何人。

如何剖析電子郵件標頭?

使用 Email::MIME 模組。它經過充分測試,支援在真實世界中會看到的各種瘋狂情況(註解折行空白、編碼、註解等)。

use Email::MIME;

my $message = Email::MIME->new($rfc2822);
my $subject = $message->header('Subject');
my $from    = $message->header('From');

如果您已經有其他類型的電子郵件物件,請考慮將其傳遞給 Email::Abstract,然後使用其 cast 方法取得 Email::MIME 物件

my $abstract = Email::Abstract->new($mail_message_object);
my $email_mime_object = $abstract->cast('Email::MIME');

如何檢查有效的電子郵件地址?

(部分由 Aaron Sherman 提供)

這並不像聽起來那麼簡單,它包含兩個部分

a) 如何驗證電子郵件地址格式正確?

b) 如何驗證電子郵件地址鎖定有效的收件者?

在不將郵件傳送至該地址並查看另一端是否有人回答的情況下,您無法完全回答部分 b,但 Email::Valid 模組將在您能做到的範圍內執行部分 a 和部分 b

我們驗證個人郵件地址的最佳建議是讓他們輸入地址兩次,就像您通常變更密碼一樣。這通常可以清除錯字。如果兩個版本相符,請將郵件傳送至該地址,並附上個人訊息。如果您收到回信,且他們已遵循您的指示,您可以合理地確定它是真實的。

較不容易偽造的相關策略是給他們一個 PIN(個人識別碼)。記錄地址和 PIN(最好是隨機的)以供後續處理。在您傳送的郵件中,包含一個連結至您的網站,其中包含 PIN。如果郵件退回,您就知道它無效。如果他們沒有按一下連結,表示他們偽造了地址,或(假設他們收到了訊息)後續處理並不重要,因此您不必擔心。

如何解碼 MIME/BASE64 字串?

MIME::Base64 套件處理這項工作以及 MIME/QP 編碼。解碼 base 64 變得像這樣簡單

use MIME::Base64;
my $decoded = decode_base64($encoded);

Email::MIME 模組可以透明地解碼 base 64 編碼的電子郵件訊息部分,因此開發人員不必擔心這一點。

如何找到使用者的電子郵件地址?

向他們索取。有如此多的電子郵件提供者,因此,不太可能由本機系統決定使用者的電子郵件地址。

組織特定電子郵件(例如 foo@yourcompany.com)的例外情況,其中政策可以在您的程式中編寫。在這種情況下,您可以查看 $ENV{USER}、$ENV{LOGNAME} 和 getpwuid($<),例如

my $user_name = getpwuid($<)

但是,除非您的政策規定,否則您仍然不能假設這是正確的。您最好向使用者詢問。

如何傳送電子郵件?

使用 Email::Stuffer 模組,例如

# first, create your message
my $message = Email::Stuffer->from('you@example.com')
                            ->to('friend@example.com')
                            ->subject('Happy birthday!')
                            ->text_body("Happy birthday to you!\n");

$message->send_or_die;

預設情況下,Email::Sender::Simplesendsend_or_die 方法在幕後使用此方法)會先嘗試 sendmail,如果它存在於您的 $PATH 中。這通常不是這種情況。如果您使用遠端郵件伺服器傳送郵件,請考慮調查其中一個傳輸類別。在撰寫本文時,可用的傳輸包括

Email::Sender::Transport::Sendmail

這是預設值。如果您可以在執行程式碼的機器上使用 mail(1)mailx(1) 程式傳送郵件,您應該可以使用此方法。

Email::Sender::Transport::SMTP

此傳輸透過 TCP 與遠端 SMTP 伺服器連線。它可以選擇使用 TLS 或 SSL,並可透過 SASL 向伺服器驗證。

告訴 Email::Stuffer 使用您的傳輸非常簡單。

$message->transport($email_sender_transport_object)->send_or_die;

如何使用 MIME 將附件新增至郵件訊息?

Email::MIME 直接支援多部分訊息。 Email::MIME 物件本身是部分,可以附加到其他 Email::MIME 物件。請參閱 Email::MIME 文件以取得更多資訊,包括所有支援的方法及其使用範例。

Email::Stuffer 在幕後使用 Email::MIME 建構訊息,並使用簡單的 attachattach_file 方法包裝最常見的附件任務。

Email::Stuffer->to('friend@example.com')
              ->subject('The file')
              ->attach_file('stuff.csv')
              ->send_or_die;

如何讀取電子郵件?

使用 Email::Folder 模組,例如

use Email::Folder;

my $folder = Email::Folder->new('/path/to/email/folder');
while(my $message = $folder->next_message) {
  # next_message returns Email::Simple objects, but we want
  # Email::MIME objects as they're more robust
  my $mime = Email::MIME->new($message->as_string);
}

Email::Folder 名稱空間中有不同的類別,用於支援各種信箱類型。請注意,這些模組通常相當有限,僅支援讀取,而不支援寫入。

如何找出我的主機名稱、網域名稱或 IP 位址?

(由 brian d foy 提供)

從 Perl 5.7.3 開始成為標準函式庫一部分的 Net::Domain 模組,可以取得完全合格網域名稱 (FQDN)、主機名稱或網域名稱。

use Net::Domain qw(hostname hostfqdn hostdomain);

my $host = hostfqdn();

標準函式庫一部分的 Sys::Hostname 模組,也可以取得主機名稱。

use Sys::Hostname;

$host = hostname();

Sys::Hostname::Long 模組採取不同的方法,並更努力地回傳完全合格主機名稱。

use Sys::Hostname::Long 'hostname_long';

my $hostname = hostname_long();

若要取得 IP 位址,可以使用內建函式 gethostbyname 將名稱轉換為數字。若要將數字轉換為大多數人預期的點分十進位制格式 (a.b.c.d),請使用 Socket 模組的 inet_ntoa 函式,它也隨附在 perl 中。

use Socket;

my $address = inet_ntoa(
    scalar gethostbyname( $host || 'localhost' )
);

如何擷取/放置 (S)FTP 檔案?

Net::FTPNet::SFTP 允許您與 FTP 和 SFTP (安全 FTP) 伺服器互動。

如何在 Perl 中執行 RPC?

使用其中一個 RPC 模組 ( https://metacpan.org/search?q=RPC )。

作者和版權

版權所有 (c) 1997-2010 Tom Christiansen、Nathan Torkington 和其他註明的作者。保留所有權利。

此文件是免費的;您可以在與 Perl 相同的條款下重新分發和/或修改它。

不論其分發方式,此檔案中的所有程式碼範例特此置於公有領域。您被允許且鼓勵在自己的程式中使用此程式碼,以供娛樂或營利,視您所見為合適。在程式碼中加上一個簡單的註解表示感謝會很客氣,但並非必要。