Fedora 9 正式版发布
下载地址:
安装介质
Sending Email With PHPMailer
This example will show you how to send HTML mail from you Cake application with PHPMailer.
You will create:
1. cakePHP component
2. a vendor package
3. view for plain text email body
4. view for HTML email body
5. a function in your controller to send mail.
Steps
Get PHPMailer
- Get PHPMailer http://phpmailer.sourceforge.net/
- Unpack it into app/vendors/phpmailer/ , so you'll have /vendors/phpmailer/class.phpmailer.php etc.etc.
Create views and layouts
- Create two views, default_html.thtml and default_text.thtml and place them in app/views/your_controller/email/
- Create a layout for the HTML part of the email, call it app/views/layouts/email.thtml
Create component
- Create new component email. Paste the following code into app/controllers/components/email.php
Component Class:
Download code <?php/**
* This is a component to send email from CakePHP using PHPMailer
* @link http://bakery.cakephp.org/articles/view/94
* @see http://bakery.cakephp.org/articles/view/94
*/
class EmailComponent
{
/**
* Send email using SMTP Auth by default.
*/
var $from = 'phpmailer@cakephp';
var $fromName = "Cake PHP-Mailer";
var $smtpUserName = ''; // SMTP username
var $smtpPassword = ''; // SMTP password
var $smtpHostNames= ""; // specify main and backup server
var $text_body = null;
var $html_body = null;
var $to = null;
var $toName = null;
var $subject = null;
var $cc = null;
var $bcc = null;
var $template = 'email/default';
var $attachments = null;
var $controller;
function startup( &$controller ) {
$this->controller = &$controller;
}
function bodyText() {
/** This is the body in plain text for non-HTML mail clients
*/
ob_start();
$temp_layout = $this->controller->layout;
$this->controller->layout = ''; // Turn off the layout wrapping
$this->controller->render($this->template . '_text');
$mail = ob_get_clean();
$this->controller->layout = $temp_layout; // Turn on layout wrapping again
return $mail;
}
function bodyHTML() {
/** This is HTML body text for HTML-enabled mail clients
*/
ob_start();
$temp_layout = $this->controller->layout;
$this->controller->layout = 'email'; // HTML wrapper for my html email in /app/views/layouts
$this->controller->render($this->template . '_html');
$mail = ob_get_clean();
$this->controller->layout = $temp_layout; // Turn on layout wrapping again
return $mail;
}
function attach($filename, $asfile = '') {
if (empty($this->attachments)) {
$this->attachments = array();
$this->attachments[0]['filename'] = $filename;
$this->attachments[0]['asfile'] = $asfile;
} else {
$count = count($this->attachments);
$this->attachments[$count+1]['filename'] = $filename;
$this->attachments[$count+1]['asfile'] = $asfile;
}
}
function send()
{
vendor('phpmailer'.DS.'class.phpmailer');
$mail = new PHPMailer();
$mail->IsSMTP(); // set mailer to use SMTP
$mail->SMTPAuth = true; // turn on SMTP authentication
$mail->Host = $this->smtpHostNames;
$mail->Username = $this->smtpUserName;
$mail->Password = $this->smtpPassword;
$mail->From = $this->from;
$mail->FromName = $this->fromName;
$mail->AddAddress($this->to, $this->toName );
$mail->AddReplyTo($this->from, $this->fromName );
$mail->CharSet = 'UTF-8';
$mail->WordWrap = 50; // set word wrap to 50 characters
if (!empty($this->attachments)) {
foreach ($this->attachments as $attachment) {
if (empty($attachment['asfile'])) {
$mail->AddAttachment($attachment['filename']);
} else {
$mail->AddAttachment($attachment['filename'], $attachment['asfile']);
}
}
}
$mail->IsHTML(true); // set email format to HTML
$mail->Subject = $this->subject;
$mail->Body = $this->bodyHTML();
$mail->AltBody = $this->bodyText();
$result = $mail->Send();
if($result == false ) $result = $mail->ErrorInfo;
return $result;
}
}
?>
Useing it in your controller
Controller Class:
Download code <?phpclass MyController extends AppController{
var $components = array('Email'); // use component email
...
function send() {
$this->Email->template = 'email/confirm';
// You can use customised thmls or the default ones you setup at the start
$this->set('data', $data);
$this->Email->to = 'someone@somewhere.com';
$this->Email->subject = 'your new account';
$this->Email->attach($fully_qualified_filename, optionally $new_name_when_attached);
// You can attach as many files as you like.
$result = $this->Email->send();
//the rest of the controller method...
}
}
?>
Credits
This is lifted almost word for word from the original piece at http://wiki.cakephp.org/tutorials:sending_email_with_phpmailer but i figured as i was about to use it, i would rewrite it for the bakery.
Enjoy.
Drayen.
Form:
http://bakery.cakephp.org/articles/view/sending-email-with-phpmailer
CakePHP你必须知道的21条技巧
原文链接:http://www.avatarfinancial.com/pages/cake/
这篇文章可以说是CakePHP教程中最经典的了。虽然不是完整的手把手系列,但作者将自己使用CakePHP的经验总结了21条,这些尤其是对新手十分有用。
翻译时故意保留了一些CakePHP中特有的词语没有翻译,如controller、model等。相信学过CakePHP的人应该马上就能理解它们的意思吧。
另外,CakePHP的wiki已经失效,取而代之的是一个名为bakery的网站。原文中引用的wiki的链接也都已更新到了bakery上。
快速创建静态页面
我想建立几个页面,它们仅包含静态数据,使用默认layout,不需要任何model。最初我试图创建一个controller并为每个静态页面定义一个action。但这种方法很笨拙,也不适合快速创建静态页面。
实际上只要使用pages controller就可以做到——只要在 views/pages 文件夹下创建一个 view,就可以通过 /pages 来访问。例如,我创建了 /views/pages/matt.thtml ,就可以通过 http://www.example.com/pages/matt 来访问。
改变静态页面的标题
使用pages controller时如果想改变页面标题,只需在view中加入以下代码:
<? $this->pageTitle = 'Title of your page.'; ?>
在静态页面中向layout发送数据
如果需要向layout传递数据(例如表示导航栏中哪个部分应该高亮显示的变量),可以在view中添加下面的代码:
<? $this->_viewVars['somedata'] = array('some','data'); ?>这个数组就可以在layout中通过$somedata来访问。
快速创建后台管理
如果你需要创建后台管理程序,并且希望所有管理action都位于某个特定文件夹下,那么打开 config/core.php 并将下面这一行的注释去掉:
define('CAKE_ADMIN', 'admin');这样所有以"admin_"开头的action都可以通过 /admin/yourcontroller/youraction 来访问。例如,如果在posts controller中创建了名为"admin_add"的action,那么可以通过 www.example.com/admin/posts/add 访问这个action。这样就可以方便地为admin目录设置密码以避免他人随意访问。
查看后台执行的SQL语句
只需改变config/core.php中的DEBUG常量,即可看到后台执行的SQL语句。 0为产品级,1为开发级,2为完整调试SQL,3为完整调试SQL并显示对象数据。我通常将DEBUG设置为2,这样每页的底部会显示出一个包含SQL调试信息的表格。
如果页面底部添加的表格会破坏页面布局(特别是使用Ajax获取页面并显示到页面中间而不是底部时),你可以在CSS中添加以下代码以隐藏调试信息:
#cakeSqlLog { display: none; }这样既能保持页面布局,又可以通过查看源代码来看到调试信息。当然最后发布网站时别忘了将调试级别改回0。
获取丰富的开发文档
别总是盯着手册。wiki和API也是无价之宝。wiki中的开发指南十分有用,而API文档初看起来比较难,但你很快就会发现这里的信息对你创建CakePHP网站十分重要。`
使用bake.php
Bake是个命令行PHP脚本,可以根据数据库自动生成model、controller和view。在开发的最初阶段,我强烈推荐使用scaffolding让你的原型程序跑起来。但如果你清楚地知道scaffolding不合适,我推荐你使用bake。 bake会生成所有的文件并保存到磁盘上,以便你随意修改。这样能节省创建关联、view、基本的CRUD crollder操作的重复工作。
(译者注:CRUD - Create, Read, Update, Delete,数据库应用的四种基本操作,即"增删查改"。)
bake很方便。你只需在数据库中建立一个表,然后到 /cake/scripts/ 目录下执行 php bake.php 即可。
如果你通过交互方式来运行bake,它会分几步提示你创建model、controller和view。创建结束之后,我通常会阅读所有生成的代码并做必要的修改。
发布程序时注意权限
有一次我在发布程序时,将整个cake目录打包然后用scp上传到了服务器上。只要一关闭调试信息,就会出现错误——数据库调用无法返回任何数据。我一筹莫展,因为我必须通过调试信息才能调试问题。后来有人告诉我,/app/tmp应当对apache可写。将权限改为777之后问题就解决了。
复杂model验证
我需要进行更复杂的验证,而不仅仅是验证输入框非空或者符合某个正则表达式这样的简单验证。例如,我要验证用户注册时使用的邮件地址是否已被使用。在wiki中我找到了这篇 关于高级验证的文章,其中提到了一些十分有用的高级验证方法。
记录错误日志
$this->log('Something broke');这样可以将错误记录到 /tmp/logs/ 中(我最初以为会记录到apache的错误日志中)。
让controller使用其他model
如果你的controller需要调用来自不同model的数据,只要在controller开头使用如下代码:
class yourController extends AppController { var $uses = array('Post','User'); }这样controller就能访问Post和User model了。
创建不使用数据库表的model
我需要创建一个不使用任何表的model。例如,我想通过$validate数组方便底验证输入数据,保持model逻辑的正确性。但创建model时对应的表不存在,CakePHP就会报错。通过在model中加入以下代码可以解决这个问题:
var $useTable = false;
你也可以通过这种方法改变model对应的表名。
var $useTable = 'some_table';
重定向之后记得exit()
对于有经验的人来说这应当是理所当然的事儿,调用 $this->redirect() 之后,剩下的代码如果不想运行要exit()。我也这样做,但以前曾经认为 $this->redirect() 会为我调用exit(实际上不会)。
高级model函数
翻翻API就能发现很多你不知道的非常有用的函数。我强烈推荐至少阅读一遍 Model 类的参考手册。下面是以前我没注意到的几个重要函数:
- generateList() - 主要用于生成选择框(<SELECT>)所需的数据
- query() - 自己写SQL语句来查询
- findCount() - 返回满足指定条件的行数
- hasAny() - 当有记录满足条件时返回真
再次强烈推荐阅读整个model类参考,你会为你学到的东西赞叹的。
如何正确插入多行
我需要遍历一个列表,并将其中的每个元素都插入到数据库中。我发现如果在一次插入完成后立即进行下一次插入,那么第二次插入的内容完全不会被插入,而是会被更新到第一次插入的行中。例如:
$items = array('Item 1','Item 2','Item 3'); foreach ($items as $item) { $this->Post->save(array('Post' => array('title' => $item))); } 这段代码将在posts表中插入仅一行:“Item 3”。 CakePHP首先插入“Item 1”,但马上将其更新为“Item 2”,再更新为“Item 3”,因为$this->Post->id保存的是上一次插入成功的行的id。通常这个特性很有用,但在这个例子中反而帮了倒忙。其实只要在每次插入之后设置 $this->Post->id = false 就可以解决这个问题。
更新:有人发邮件告诉我,正确的做法是调用create()初始化model,再set/save新数据。
在controller函数之前或之后插入逻辑
假设你需要在controller渲染的每个view中都设置一个颜色数组,但你不希望在每个action中都定义它。可以通过 beforeRender() 回调函数来实现:
function beforeRender() { $this->set('colors',array('red','blue','green'); }这样该controller渲染的所有view都可以访问$colors变量。 beforeRender() 函数在controller逻辑结束后、view被渲染之前执行。同样, beforeFilter() 和afterFilter() 函数会在每个controller action执行的前后执行。更多信息请阅读手册的models一节。
为CakePHP添加所见即所得编辑器
这里有一篇非常好的教程教你如何在 CakePHP中使用TinyMCE。基本上你只需在页面上链接tiny_mce.js文件,然后添加一些初始化代码以设置将哪个textarea变成TinyMCE编辑器即可。
自定义HABTM关系的SQL语句
我曾试图在自定义的SQL语句上定义一个HABTM关系(has-and-belongs-to-many),却遇到了问题。根据本文撰稿时的文档,应当先在自己的model中设置finderSql,但从CakePHP的源代码来看,应该设置finderQuery。这只是文档中的一个小问题,但指出问题却能为他人节约时间。 Trac ticket在这里。
发送邮件
我在wiki中找到两篇教程:发送邮件和 通过PHPMailer发送邮件。强烈推荐后者,通过PHPMailer发送邮件更安全,而且不需要自己处理邮件头,减少许多麻烦。
自定义Helper生成的HTML
我需要修改调用$html->selectTag()时生成的<option>,使其生成“请选择”选项来代替默认的空白选项。我也希望单选按钮能带有标签,这样用户就无需精确地点击单选按钮本身,而只需单击到关联的文字上即可。
建立 /app/config/tags.ini.php,然后添加以下的内容:
; Tag template for a input type='radio' tag. radio = "<input type="radio" name="data[%s][%s]" id="%s" %s /><label for="%3$s">%s</label>" ; Tag template for an empty select option tag. selectempty = "<option value="" %s>-- Please Select --</option>"
你可以从/cake/config/tags.ini.php中获得完整的标签列表。但我不建议修改该文件,否则升级CakePHP时可能会让你的修改丢失。
自定义404页面
如果你需要自定义404页面,只需创建 /app/views/errors/error404.thtml。
ubuntu对技术白痴型女友来说足够易用吗?
让女友试用Ubuntu
简介
我从2002年开始倒腾Linux到现在这么多年过来了,我想看看新出的Linux系统是不是对于大部分人来说已经足够易用,于是我让女友Erin用新安 装的Ubuntu 8.04来完成一些基本任务。结果有些令人吃惊,很多看似简单的任务对于过去没有使用Linux经验的人来说依旧非常困难。Linux还有很多需要改进的 地方以使其能给“电脑白痴们”提供更好的用户体验。
Erin具备一些基本的计算机知识,比如上网、打字、制表和照片处理等,这对于一个哲学系大学生来说已经足够了。在用于实验的Ubuntu系统 上,我提前为她设好了帐户。她可以轻松的登录进去,她很喜欢heron(Ubuntu 8.04 Hardy Heron)的壁纸。接着我便将设计好的任务一一让她完成,而我不提供任何帮助。
任务一:告诉我波黑的首都在哪里
Erin很快找到了Firefox的链接,然后在wikipedia上找到了问题的答案:萨拉热窝。
任务二:在YouTube上看视频
(注:这是YouTube所特有的问题,它会主动检测你机器上是否有Flash插件,如果没有,它给出一个Adobe的网页让你去下载。而正常情况下Firefox会自动帮你下载Flash插件。碰巧让我选上了YouTube算是运气不好)
Erin在试图播放YouTube上一段Beatles的视频时,YouTube提示它需要去Adobe官方下载所需的Flash插件,而在 Adobe主页上有.tar.gz、RPM和YUM三种格式的包。RPM和YUM显然无法在Ubuntu上使用。Erin点击了.tar.gz包中的 flashplayer-install也没有任何反应,因为这个程序只能在terminal下运行。最终Erin无法完成这个任务。(译者注:YouTube好心帮了倒忙)
任务三:下载一部辣妹的专辑
Erin的第一反应就是去在应用程序菜单中找Limeware的替代品,接着她还尝试运行Windows版的uTorrent,结果均告失败。然后她找到 了一个下载BitTorrent种子文件的网站,点击了一个辣妹专辑的torrent文件之后,Firefox提示是否要用Transmission打开 此文件。Erin犹豫了一下,点了确定,很快这部专辑便被下载到了她的桌面。
我觉得这里唯一的问题是Firefox所提示软件的名称,如果提示是“是否用Transmission BT客户端打开此文件”,那么可以减少很多麻烦。(译者注:在应用程序菜单中就是用的“Transmission BT客户端”这样比较易懂的名称,当然要是不知道BitTorrent是什么,看这个名字还是云里雾里的,类似的名称问题在任何系统中都是无法避免的)
任务四:画一副图,并保存为3种不同的格式
Erin很快在“图像”菜单中找到了“OpenOffice.org绘图”,与她所期待的一个类似Windows的简易画图软件不同, “OpenOffice.org绘图”是一个非常复杂的矢量绘图软件。最终她完成了任务,不过她不知道用“导出”命令将图片转换为熟悉的格式,而是用了 “另存为...”将图片存成了的.odg、.otg和.sxg格式。我无法理解为什么Ubuntu不提供一个像KPaint一样简单的画图程序。(同时我 也奇怪为什么OpenOffice.org绘图会在标准安装里,我从没见过谁用过这样的程序)(译者注:无语,我就在用,它实际上是OOo很重要的一个组成部分,和“Microsoft Word 图片”控件很类似。另外我还在用看上去更不可理喻的Xfig,相反KPaint一类的画图软件对我倒是毫无用处)
任务五:从我的音乐收藏中找一首专辑,并将其刻录到CD上
Erin找到了“Brasero光盘刻录程序”,它的界面很不错。但当Brasero提示添加所要刻录的歌曲的时候,Erin却找不到存放音乐的 Windows分区。她找了Ubuntu默认建立的Music目录,Home目录和桌面,但是错过了"492.8GB Media",也就是那个Windows分区,她也没有仔细去看“文件系统”,那里面怪异的名称让她望而却步。之后她在“位置”菜单中找到了搜索程序,但 她只尝试了搜索Home目录和Music目录,而没有试“文件系统”。后来她告诉我那个程序不能根据文件类型搜索,实在是太笨了。
Ubunbu应该更清楚的显示其他分区在什么地方,分区的快捷方式也应该使用更有意义的名称。另外,搜索程序应该增加一个搜索“整个电脑”的选项以替代“文件系统”。没有经验的用户很难搞清楚“etc”、“dev”和“mnt”等等目录是干什么的。(译 者注:作者有点吹毛求疵了。我认为Ubuntu在这方面已经非常尽力了,如果分区有卷标的话,那个分区快捷方式的名称将使用卷表名,如没有则显示存储容 量,U盘没有挂载的时候显示的则是生产厂商的名称和容量。另外,也许“整个电脑”对于新手来说更为容易理解,不过“文件系统”这个术语在这里要准确得多, 特别是考虑到有虚拟挂载点、网络挂载点时候)
任务六:改变鼠标的速度
没啥问题,她很快就搞定了
任务七:改变电脑的主题
也很轻松就弄好了
任务八:在网上找一幅图片,将其设为桌面
Firefox的右键菜单中没有将图片直接“设置为背景”的功能。不过她还是顺利解决了。
任务九:改变屏幕分辨率
她在系统属性菜单中找到了屏幕分辨率设置程序,并将分辨率改为720x400。然而,由于这个分辨率太低,使她无法看到设置程序最下方的确定按钮,也就没 有办法把分辨率调回原来的设置。最后我只好在看不见的情况下用tab键切换到确定按钮上。如果屏幕分辨率很低,这个程序根本没法使用。(译 者注:这确实是Ubuntu/Gnome需要改进的地方,如果这个设置程序最上方有个菜单可能能避免不少类似的问题。考虑到这是Ubuntu第一次使用此 程序,有点这样的小毛病也情有可原,实际上Windows也同样的问题。目前有一个凑合的办法,按Alt-F7,然后再按方向键,可以将窗口上移)
任务十:将她的头像PS到我的照片上
她通过右键菜单用GIMP打开了我们俩各自的照片。她有一些Photoshop的基础,而GIMP的不同风格界面使她有点迷惑,度过了开始一段不适应之后,她还是完成了任务。我不明白为什么GIMP的排版布局不能像Photoshop一样呢。(译者注:我不是GIMP或者Photoshop的专家,不敢在这个总是引发口水仗争议问题上乱发言,不过我个人觉得,在多桌面、多显示器的环境下,GIMP的界面布局还是有它的合理性的。而作为免费的非专业照片处理软件,GIMP的功能也不错了)
任务十一:登录MSN
Erin在应用程序菜单中的互联网子菜单里找到了“Pidgin即时通讯软件”。她问我这个是否就是MSN,我回答不完全是,于是她打开了Pidgin。 当Pidgin提示她增加一个帐户的时候,她被帐户设置里选项所迷惑,比如“screen name”、“local alias”,这些术语在她所熟悉的MSN中从没有出现过。经历了好几次失败的尝试之后,Erin终于登录上了MSN,这也让她可以向朋友们诉苦 Linux有多讨厌。
如果Pidgin有一个欢迎窗口告诉用户Pigin是做什么的,并询问是否要增加或登陆MSN等帐号,那么Erin的问题就很容易解决。如果 “screen name”能根据不同类型的协议使用不同的术语,那也会很有帮助。另外,“local alias”是具体做什么的也给新手造成了很多困惑。
当Erin试图退出Pidgin的时候,她以为直接点右上角的关闭按钮即可,但实际上Pidgin退到了屏幕右上角的系统提示区。Erin又花了一些时间才找到那个图标。当你第一次关闭Pidgin的时候,它应该提示这个程序并没有真正退出,而只是缩到了系统提示区。(译 者注:作者的这几个建议非常好,用了很久的Pidgin/Gaim之后,我都有些忘记了最开始的一些挣扎,其实开始我也遇到过弄不清screen name/local alias/friendly name具体意义的情况,如果Pidgin能做一个wizard来添加IM协议,那可以大大方便初学者,我印象中好像有些Pidgin/Gaim的变种就 有这样的功能,希望Pidgin也能采用)
任务十二:安装Skype
Erin去了skype.com,很容易就找到了适合Ubuntu的.deb安装包,并顺利安装。唯一的问题是,她不知道Skype装到哪里去了,不知什么原因,她没有去看网络程序菜单。如果有像Windows一样提示“有新程序安装”就可以解决这个问题了。
结论
Ubuntu桌面体验的最主要问题是程序设计者对一般用户的水平做出了太高的假设。他们假设用户知道程序是怎么安装或者知道文件系统是怎样构架。而普通用 户遇到问题是不会去google搜寻帮助或者去读Ubuntu自带的相关文档的。一些简单的信息提示和向导可以对用户完成一些任务有关键性的帮助。
我希望一登录进入桌面就能看到一个欢迎画面,上面有一些小的视频解释Linux和Ubuntu的基本概念。也许它还可以问“你想做什么?”,然后根据选择去解释具体如何做。
直到一个电脑盲可以坐在Linux系统前不费力气的完成她想做得事情,Linux都不能说已经为桌面应用做好准备。Erin很聪明,学得快,现代科技的知识也算充足。如果她都会有这么大麻烦,那老年人或者中年人还有多少机会呢?
译者注:本文作者对 Linux易用性的某些缺陷的分析很不错,给出的解决方案也相当好,但是他最后的结论我却很难赞同。事实上,Erin能在没有得到作者的任何帮助,也没有 通过网络搜索的情况下完全依赖原有的Windows知识,在一套干净的Ubuntu 8.04上基本完成了所有的任务,这已经标志着Ubuntu易用性设计的很大成功了。计算机系统本身的复杂性就决定了使用新系统的时候所需的学习成本是不 可避免的,就算从WinXP升级到Vista也不可能一帆风顺。这种成本的存在并不能简单归结为Linux系统的易用性差。实际上已经有很多实例反证了作 者的猜想,经过简单的指导,中老年人完全可以顺利的使用一台配置好的Linux系统。
出自:Ubuntu中文论坛
Ubuntu 8.04正式版发布下载!
下载主页:
http://releases.ubuntu.com/releases/8.04/
直接下载:
http://releases.ubuntu.com/releases/8.04/ubuntu-8.04-desktop-i386.iso
64位的:
http://releases.ubuntu.com/releases/8.04/ubuntu-8.04-desktop-amd64.iso
如果你的机子没有384M内存,下载以下版本:
http://releases.ubuntu.com/releases/8.04/ubuntu-8.04-alternate-i386.iso
64位的:
http://releases.ubuntu.com/releases/8.04/ubuntu-8.04-alternate-amd64.iso







