[ 永远的UNIX::UNIX技术资料的宝库 ]

首页 > 编程技术 > Perl > 正文

Perl Cookbook 2介绍

作者:saladjonk 来源:Perlchina (2005-07-10 22:07:09)

 编者的话:最新版的 Perl Cookbook 马上就要放上书店的书架开始发售了,这里我们介绍一些第二版里没有的内容,你可以先看看这些节选的内容。这周我们要介绍的是从第14章“数据库操作”和第十八章“互联网服务”中节选的内容。一定记住下周还来这个地方哦,我们会介绍脱离数据库来使用 SQL 语言,从表格中提取数据,用 HTML::Mason 模板进行网页模板编程等。

摘要:SQL 语言在标准数据库以外的应用

问题:你想对一个非关系型数据库结构进行复杂的 SQL 查询。

解决:使用 CPAN 上的 DBD::SQLite 模块

use DBI;

$dbh = DBI->connect("dbi:SQLite:dbname=/Users/gnat/salaries.sqlt", "", "",
          { RaiseError => 1, AutoCommit => 1 });

$dbh->do("UPDATE salaries SET salary = 2 * salary WHERE name = 'Nat'");

$sth = $dbh->prepare("SELECT id,deductions FROM salaries WHERE name = 'Nat'");
# ...

讨论:

SQLite 模块定义的“数据库”是存在于单个文件中的,把单个文件仿真为一个数据库。在用 DBI 连接时,dbname 参数指定为该文件名。不像大多数的关系型数据库,在 DBD::SQLite 定义的数据库不是服务器/客户短架构,没有服务器,它直接与文件交换数据。多个进程可以同时从一个文件中读取数据(此时用 SELECTs 命令),但是只有一个进程能向文件中写数据(当一个进程写数据的时候其它的进程被挂起)。SQLite 支持事务功能,也就是,你可以向多个表做出一系列改动,但是只要你不向 SQLite 提交这些改动,更新就不会写到文件中。
use DBI;
$dbh = DBI->connect("dbi:SQLite:dbname=/Users/gnat/salaries.sqlt", "", "",
          { RaiseError => 1, AutoCommit => 0 });
eval {
 $dbh->do("INSERT INTO people VALUES (29, 'Nat', 1973)");
 $dbh->do("INSERT INTO people VALUES (30, 'William', 1999)");
 $dbh->do("INSERT INTO father_of VALUES (29, 30)");
 $dbh->commit( );
};
if ($@) {
   eval { $dbh->rollback( ) };
   die "Couldn't roll back transaction" if $@;
}
SQLite 定义的数据库里面没有数据类型这个概念。不管你在创建一个表的时候指定的是什么数据类型,以后你可以在其中放入任何类型的数值(包括字符型,数字型,日期型,二进制对象/blob)。实际上,创建表的时候你甚至可以不指定数据类型。
CREATE TABLE people (id, name, birth_year);
SQLite 只有在要比较数据的时候,如用 WHERE 子句或对某些值进行排序,才会考虑数据类型。SQLite 在比较数据的时候,只考虑被比较对象的类型,而不管被比较对象所在列的其它数据是什么类型。像 Perl 一样,SQLite 只能识别字符型和数字型。两个数值总是以浮点类型进行比较,两个字符串直接比较。当不同类型的数据比较的时候,数字总是比字符小。 只有一种情况 SQLite 才会关心你为某一列申明的数据类型(需要创建一个值自增加的列的时候)。你可以把这列的类型指定为:“INTEGER PRIMARY KEY”。
CREATE TABLE people (id INTEGER PRIMARY KEY, name, birth_year);
例子 14-6 说明这一切是怎么工作的
例 14-6 整形主键
 #!/usr/bin/perl -w
 # ipk - demonstrate integer primary keys
 use DBI;
 use strict;
 my $dbh = DBI->connect("dbi:SQLite:ipk.dat", "", "",
 {RaiseError => 1, AutoCommit => 1});
 # quietly drop the table if it already existed
 eval {
  local $dbh->{PrintError} = 0;
  $dbh->do("DROP TABLE names");
 };
 # (re)create it
 $dbh->do("CREATE TABLE names (id INTEGER PRIMARY KEY, name)");
 # insert values
 foreach my $person (qw(Nat Tom Guido Larry Damian Jon)) {
  $dbh->do("INSERT INTO names VALUES (NULL, '$person')");
 }
 # remove a middle value
 $dbh->do("DELETE FROM names WHERE name='Guido'");
 # add a new value
 $dbh->do("INSERT INTO names VALUES (NULL, 'Dan')");
 # display contents of the table
 my $all = $dbh->selectall_arrayref("SELECT id,name FROM names");
 foreach my $row (@$all) {
  my ($id, $word) = @$row;
  print "$word has id $id\n";
 }


SQLite 支持 8 位长的字符编码,但是不识别 ASCII 中的 NULL 符“\0”。唯一的变通方法就是在你存储数据之前自行编码,然后在取出数据之后再手工解码,就象 URL 编码或 Base64 编码方式一样。 这甚至可以用在 BLOB 字段里面。

参照:“Executing an SQL Command Using DBICPANDBD::SQLite 模块的正式文档。它在 SQLite 的主页上 http://www.hwaci.com/sw/sqlite

 

摘要:发送邮件的时候添加附件

问题:你想要发一封包含附件的邮件,比如包含一份 PDF 格式的文档

解决:用 CPAN 上的 MIME::Lite 模块。

首先,创建包含邮件各种头信息的 MIME::Lite 对象:
use MIME::Lite;

$msg = MIME::Lite->new(From  => 'sender@example.com',
            To   => 'recipient@example.com',
            Subject => 'My photo for the brochure',
            Type  => 'multipart/mixed');
然后用 attach 方法添加附件内容:
$msg->attach(Type    => 'image/jpeg',
       Path    => '/Users/gnat/Photoshopped/nat.jpg',
       Filename  => 'gnat-face.jpg');

	

$msg->attach(Type => 'TEXT',

Data => 'I hope you can use this!');
 
最后,发送这份邮件,发送它的方法是可选的:
$msg->send( );      # 默认的方法是用sendmail规则发送
# 指定其它的方法
$msg->send('smtp', 'mailserver.example.com');

 

讨论:

MIME::Lite 模块创建并发送带 MIME 指定类型附件的邮件。MIME 是 Multimedia Internet Mail Extensions 的缩写,而且也是在邮件中附带各种文件文档的标准方式。但是,这个规则并不能从邮件信息中把附件提取出来。如果你想从邮件信息中提取MIME指定类型附件,可以参考这篇文章“Extracting Attachments from Mail”

当你创建 MIME::Lite 对象,以及向创建的对象中添加内容的时候。后面的参数采用“参数名=>值”的有名对形式。有名对的参数名部分应该暗示它代表的邮件头(如,From,To,Subject)以及其它其它 MIME::Lite 所特有的东西。如果参数名是邮件头,后面应该加上冒号,如:
$msg = MIME::Lite->new('X-Song-Playing:' => 'Natchez Trace');

然而,当参数名代表的邮件头在表 18-2 中时,后面可以不加冒号。下表中 * 代表通配符,例如 Content-* 可以代表 Content-Type 和 Content-ID 但是不代表 Dis-Content

表 18-2: MIME::Lite 头

Approved Encrypted Received Sender
Bcc From References Subject
Cc Keywords Reply-To To
Comments Message-ID Resent- X-
Content-* MIME-Version Return-Path
Date Organization

MIME::Lite 参数类型的完整列表在表 18-3 中

表 18-3: MIME::Lite 参数类型

Data FH ReadNow
Datestamp Filename Top
Disposition Id Type
Encoding Length
Filename Path

MIME::Lite 模块的参数类型决定附件的类型和附件的添加方法:

Path 指定作为附件的文件的路径
Filename 指定接受方保存附件时,附件的默认文件名。如果指定了 Path 参数,那么默认的文件名就是路径中的名字
Data 指定附件添加的日期
Type 指定待添加附件的文件编码类型
Disposition 它的值只能是 inline 和 attachment。前者指定接受方打开邮件的时候附件内容会跟在邮件正文后显示,而不单独作为一个附加物。后者指定接受方应该指定一个附件的解码方法,并且保存附件,此时会有提示
FH 指定一个读取附件的开放的文件句柄

这儿有几个有用的附件编码类型:TEXT 代表 text/plain,为 Type 的默认值;BINARY 是 application/octet-stream 的缩写;multipart/mixed 表明邮件有附件;application/msword 表明附件为微软的 Word 文档;application/vnd.ms-excel 表明附件为微软的 Excel 文档;application/pdf 表明附件为 PDF 文档;image/gif,image/jpeg,image/png 分别指定 GIF,JPEG,PNG 文件;audio/mpeg 指定 MP3 格式文件;video/mpeg 指定 MPEG 格式影片;video/quicktime 指定Quicktime 格式文件。

发送邮件的唯一两种方法是 sendmail 和 Net::SMTP。调用 send 方法时,若第一个参数为“smtp”,则用 Net::SMTP 发送邮件。send的其它参数都传给 Net::SMTP。
# timeout of 30 seconds
$msg->send("smtp", "mail.example.com", Timeout => 30);
如果你想创建多个 MIME::Lite 对象,也就是发送多附件,你可以把 send 作为类方法调用,此时默认发送方法会被替换。
MIME::Lite->send("smtp", "mail.example.com");
$msg = MIME::Lite->new(%opts);
# ...
$msg->send( ); # sends using SMTP

如果你要处理多个消息,用好 ReadNow 参数。它指定附件应该立即从文件或文件句柄中读取发送,而不是在发送前转化为字符串。

发送邮件不是 MIME::Lite 能做的唯一事情。你还可以用它把最后的邮件内容变成字符串:

$text = $msg->as_string;
print 方法可以把消息的字符串形式写入一个文件句柄自定的文件中:
$msg->print($SOME_FILEHANDLE);
例子 18-3 是一个发送邮件的程序,它把在命令行输入的文件名作为附件 例 18-3 :发送带附件的邮件
#!/usr/bin/perl -w
# mail-attachment - send files as attachments

use MIME::Lite;
use Getopt::Std;

my $SMTP_SERVER = 'smtp.example.com';      # 可根据自己情况改变
my $DEFAULT_SENDER = 'sender@example.com';   # 同上
my $DEFAULT_RECIPIENT = 'recipient@example.com';# 同上 

MIME::Lite->send('smtp', $SMTP_SERVER, Timeout=>60);

my (%o, $msg);

# process options

getopts('hf:t:s:', \%o);

$o{f} ||= $DEFAULT_SENDER;
$o{t} ||= $DEFAULT_RECIPIENT;
$o{s} ||= 'Your binary file, sir';

if ($o{h} or !@ARGV) {
  die "usage:\n\t$0 [-h] [-f from] [-t to] [-s subject] file ...\n";
}

# construct and send email

$msg = new MIME::Lite(
  From => $o{f},
  To  => $o{t},
  Subject => $o{s},
  Data => "Hi",
  Type => "multipart/mixed",
);

while (@ARGV) {
 $msg->attach('Type' => 'application/octet-stream',
        'Encoding' => 'base64',
        'Path' => shift @ARGV);
}

$msg->send( );

(http://www.fanqiang.com)

原文链接:http://www.perlchina.org/archive/archive.php?action=archive&page=45

 相关文章

★  感谢所有的作者为我们学习技术知识提供了一条捷径  ★
www.fanqiang.com