• "饭否图片上传" 按钮. 

    FanfouPic

    将链接添加为书签, 使用时点击该书签按钮即可.

    截图:

     

    === 使用方法 ===

    .方法 1

    将按钮拖到书签工具栏, 使用时点击该书签即可.

     

    .方法 2

    鼠标右键按钮, 选择"添加到收藏夹"即可.

     

    .方法 3

    鼠标右键按钮,选择右键菜单中的“复制链接地址”,然后手动添加书签:名称填写"启用搜狗云输入法",地址粘帖复制的内容。或者,直接将下面的搜狗云输入法按钮拖到浏览器的书签栏。

     

    源代码: github

  • 每个系统有一个全局 crontab 文件, 位于 /etc/crontab.

    每个用户可以有自己独立的 crontab 文件, 位于 /var/spool/cron/crontabs , 但该文件并不设计为手动编辑的, 正确的方法是使用 crontab -e 来编辑自己的 crontab 文件.

    编辑自己用户的 crontab 文件

    crontab -e

    格式是:

    # m h dom mon dow command
      * *  *   *   *  curl http://yiriji.com/admin/cron
    • m, 分钟

    • h, 小时

    • dom, day of month, 日期

    • mon, month, 月份

    • dow, day of week, 星期

    和全局的 crontab 不同的是, 没有用户名这一列

    如果因书写错误, 则可以到 /var/mail/用户名 文件中查看到错误信息.

    Ubuntu中命令
    /etc/init.d/cron start
    /etc/init.d/cron stop
    /etc/init.d/cron restart
    Ubuntu中的全局crontab文件示范:
    # m h dom mon dow user  command
    
    # 每天每个小时的第17分执行 /etc/cron.hourly 文件下的所有可执行程序或脚本
    17 *    * * *   root    cd / && run-parts --report /etc/cron.hourly
    
    # 每天6点25分执行
    25 6    * * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
    
    # 每个星期天的6点47分执行
    47 6    * * 7   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
    
    # 每月1号6点52分执行
    52 6    1 * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )

    run-parts 的意思就是执行该文件夹下所有可执行程序或脚本.

  • 在Apache下设置 Expires Header , 使得图片,CSS, JS得以被浏览器缓存, 以加快页面载入速度.

    首先确定apache加载了 mod_expires .

    错误示范

    网上提供在 .htaccess 里面使用 expires 的方法都是:

    ExpiresActive On
    ExpiresDefault A0
    ExpiresByType image/gif A2592000
    ExpiresByType image/png A2592000
    ExpiresByType image/jpg A2592000
    ExpiresByType image/jpeg A2592000
    ExpiresByType image/ico A2592000
    ExpiresByType text/css A2592000
    ExpiresByType text/javascript A2592000
    ExpiresByType text/html M604800
    Note
    以上设置只会缓存图片, image/* .

    但是 实验证明将它们写入 .htaccess 后,会只有image/* , text/css 会被加上 expires 头,而javascript和ico都 不会 被长期缓存.

    原因是因为apache的 expiresByType 是根据浏览器请求头中 Accept 来决定的, 浏览器在请求图片的时候会自动在请求头上根据图片类型加上:

    Accept:  image/png, image/*;q=0.8, */*;q=0.5

    而在请求javascript脚本的时候只会发送

    Accept: */*

    浏览器并不会指明请求类型为 text/javascript , 所以apache的 ExpiresByType 就捕捉不到该类型, 也就不会加上 expires 头.

    正确方法

    因此正确的替代方法是使用 FilesMatch 来替代 ExpiresByType, 例如:

    
        ExpiresActive On
        ExpiresDefault "access plus 1 year"
    

    同样可以加入到 .htaccess 里使用.

  • Git-Diff-Fileset

    本工具利用Git等代码仓库生成的 diff (patch)文件, 复制得到一份两次提交之间的差异文件集. (保留目录结果, 文件信息).

    该工具意在用于网站程序上线后, 在本地进行了多次代码更新, 需要使用FTP等工具本地将修改的文件集批量上传到服务器, 得到服务器和本地代码同步.

    1. 用例

    假设你已经将整个应用程序的代码上传到服务器, 然后在本地进行了功能扩展, 修改或增加了一部分文件, 而在本地测试完毕后需要将它们上传到服务器. 在上一次与服务器同步之后, 你在本地进行了一次代码提交. 例如你的 commit log :

    commit 2 5b6a52ea652eec20871c6285e00a03bef785edcc
    Date:   Thu Apr 28 12:35:31 2011 +0800
    
    commit 1 e4ef18425c6c49aefa92bb46c847be16b2de019e
    Date:   Thu Apr 28 11:34:05 2011 +0800

    commit 1 的文件和服务器是同步的, 你只需要将 commit 2 的修改集上传到服务器.在在commit 2中你一共修改了三个文件:

    M /css/style.css
    M /js/script.js
    M /index.php

    1.1. 生成Patch文件

    利用git diff命令生成补丁文件.

    git diff master^ > change.diff

    1.2. 得到修改集文件拷贝

    使用本工具得到一个修改集, 并保留目录结构和基本文件信息(最后修改时间等).

    java --jar git-diff.jar -dir /path/to/your/project change.diff

    其中dir参数为你的代码跟目录, 即 .git 文件夹的所在; change.diff 为上一步生成的补丁文件.

    之后便得到一个拷贝目录, 将包含此次提交的所有修改文件:

    /copy/
    /copy/index.php
    /copy/css/style.css
    /copy/js/script.js

    1.3. 使用FTP上传到服务器

    你只需使用喜欢的FTP客户端, 把这个目录上传到服务器上相对应的目录即可.

    然后可以冲杯茶, 让代码飞一会.

     

    下载地址: 源代码

  • 使用HTML缓存可以使得一些对动态要求不高的页面请求更快,也缓解了服务器压力, 比如一些固定的文章页.

    而使用Zend Framework构建的应用程序将 非常简单 的可以把服务器输出的内容缓存为html文件, 再之后的请求中, 完全就没有PHP和Zend Frameword什么事了, 只是简单的请求html文件即可, 快速而高效.

    但是可惜的是介绍相关内容的资料非常之少, 就连官方手册中也只是对该功能提了一下, 并没有给出完成的用例说明.

    这里不仅是介绍如何使用 Zend_Cache 将Zend Framework生成的页面缓存为HTML的方法, 也对其实现方法和原理进行了一些分析, 可不局限与ZF框架, 对PHP生成HTML静态缓存技术有进一步的了解, 同时也研究了ZF是如何利用这些基本缓存技术来实现对整个ZF应用生成的内容进行缓存.

    1. PHP生成HTML缓存

    首先简单将一些PHP生成HTML缓存的原理, 这有助于我们理解Zend_Cache是如何缓存整个页面的.

    首先我们大概都知道 ob_start 函数, 虽然可能很少用过, 但一定见过, 在一般情况下, 我们需要截获PHP输出内容, 一般会使用到这个函数, 例如:

    
    
    // 开始缓存输出
    ob_start();
    
    // 模拟读取数据库之类等耗时操作
    $foo = $db->fetchAll("SELECT * FROM {node}");
    
    // 模拟向客户端输出内容
    echo $foo;
    
    // 因为之前调用了ob_start(), 所以这里并不会立刻输出到客户端
    
    // 而我们可以截获到输出内容
    $buffer = ob_get_contents();
    
    // 将输出内容缓存到文件
    file_put_contents($buffer, '/tmp/cache.html');
    
    // 将之前的ob缓存释放到客户端
    ob_end_clean();
    

    ob_start 是提供另一种形式的, 就是 ob_start(callback) , 其中 callback 为指定的回调函数名, 该回调函数可能会在如下情况下被调用:

    • 调用 ob_flush() , 部分输出内容发送到客户端.

    • 调用 ob_clean() , 输出内容发送到客户端.

    • 该请求终止时, 输出内容自动发送到客户端.

    例子
    
    
    function myCallback($buffer) {
        file_put_contens($buffer, '/tmp/cache.html');
    }
    
    
    ob_start('myCallback');
    
    echo '';
    
    ob_end_flush();
    

    这里我们就基本了解了PHP生成HTML的原理, 接下来我们再来看Zend Framework这种具有比较复杂的系统如何来利用该原理实现HTML静态化的.

    2. Zend_Cache_Backend_Static

    Zend Frameword 中内置的实现HTML静态化的组件就是 Zend_Cache_Backend_Static , 其属于 Zend_Cache 模块. 因此在了解它之前, 你必须了解 Zend_Cache 的原理和使用方法, 这里并不简介, 可以查看手册 Zend_Cache .

    Zend_Cache_Backend_Static 作为cache backend, 其必须和cache frontend中的 Zend_Cache_Frontend_Capture 配合使用.

    2.1. 内部实现

    这里先讲解一下 Zend_Cache_Backend_Static 这个类, 在使用HTML静态化时可以不需要了解这个部分, Zend framework 提供了封住好的 helper 类, 不需要了解实现细节的可以跳过该小节.

    Zend_Cache_Backend_Static 的内部实现使用的其实只 Core, File 组合的一个 innerCache , 这里其实也很好理解, 因为它的功能就是将内容输出到文件, 所以就直接使用了 Zend_Cache_Backend_File 作为缓存到文件的功能, 当然这里并不需要去完全理解它, 除非你想要去自己实现 innerCache , 通过设置 Zend_Cache_Backend_Statictag_cache 可以指定自己的 innerCache , 也可以调用 setInnerCache() 来完成.

    Zend_Cache_Backend_Static 基本上只有一个外部接口是最值得关注的, 就是 save 方法: boolean save (string $data, string $id, [array $tags = array()], [int $specificLifetime = false])

    参数:
    • $data , 是需要缓存的内容.

    • $id , 是缓存的ID.

    例如调用: $cache->save("bar : data to cache", bin2hex("/bar"));

    将会把 "bar : data to cache" 作为文件缓存到 "public/bar.html" (默认设置情况下).

    这里也就了解了ZF将会如何去缓存输出到HTML了, 基本上就是通过截获 ob_start 储存起来的输出缓存, 然后把该缓存作为 save$data 参数即可.

    3. Zend_Controller_Action_Helper_Cache

    action helper 则是ZF为我们提供的一个封装好的帮助类, 使用它, 我们基本不需要做任何额外的操作就可以把整个action页缓存成html文件.

    既然是 action helper , 那么也就是说ZF提供 Zend_Cache_Backend_Static 这种缓存技术和其他的几个缓存组件并不一定, 它是属于 Controller 级别的缓存, 旨在将某几个 action 页面进行整体缓存, 使用方法也是在 Controller_Action#init 中进行使用的.

    这里先讲准备功能, 就是提供少数几个推荐提供给 Zend_Cache_Backend_Static 的参数:

    3.1. 步骤1: 配置文件

    ; Cache - static
    resources.cachemanager.page.backend.options.public_dir = APPLICATION_PATH "/../public/cached"
    resources.cachemanager.pagetag.backend.options.cache_dir = APPLICATION_PATH "/data/cache/tags"
    resources.frontController.params.disableOutputBuffering = true
    Note
    注意大小写, cachemanagerm 是小写, 而 frontControllerC 是大写, 因为这个大小写的原因害我浪费了一天的时间.
    public_dir

    一个是 public_dir , 默认的是 ../public , 而有时我们需要把静态文件放置到统一的文件夹中, 如果指定了该文件夹, 并且该文件夹不存在, 就必须确保PHP有 mkdir 此文件夹的权限, 如果该文件夹你创建好了, 那么就必须确保PHP有读写的权限. 我的建议是把这个文件夹创建好, 然后给个比较大的权限 0777 之类的做测试用, 已排除是文件权限导致的静态化失败, 特别是linux系统.

    这个文件夹的制定很重要, 手册上推荐的是使用绝对路径(可以使用APPLICATION_PATH). 而且必须保存该文件夹可写, 而且创建HTML文件时就会失败.

    Note
    需要给linux系统的某些用户提醒下就是, PHP生成的HTML文件所有者会是 www-data 之类的apache用户, 而且缓存文件的权限可能只有所有者可读, 你可能会永远看都是空文件夹, 因为你可能没有权限查看该文件夹下的内容 可能ZF已经为你生成了缓存的HTML文件到缓存目录, 而你查看文件夹时会发现总是空, 这是权限问题, 如果你用su用户查看, 就会发现HTML文件已经在那里了.
    disableOutputBuffering

    手册上也明确写出了如果要使用该静态缓存功能, 就必须将 disableOutputBuffering 设置为 true , 该选项的功能是关闭 frontController的 outputBufering, 因为默认情况下, 在frontController里面是会使用到 ob_start 的, 而这里我们需要关闭它, 使得我们可以在 Zend_Cache_Backend_Static 中来调用 ob_start(callback) 来缓存所有内容.

    3.2. 步骤2: init()

    唯一需要做的就是在 init() 内部利用cache helper来制定哪几个action是需要被缓存的即可.

    
    
    class Node_IndexController extends Zend_Controller_Action
    {
    
        public function init()
        {
            $this->_helper->cache(array('index', 'page'), array('allentries'));
        }
    
        public function indexAction()
        {
            echo "index action cache";
        }
    
        public function pageAction()
        {
            echo "page action cache";
        }
    
    }

    这时你访问 /node/index/index 就会发现你指定的缓存目录下会出现 /node/index/index.html 文件了. 比如你访问 /node 那么就会在缓存目录下直接生成 /node.html , 都是请求路径和缓存目录的路径一一对应的.

    Note
    cache helper是支持 Zend_Layout 的, 生成的内容会包含layout.

    3.3. 步骤3: .htaccess

    修改 .htaccess 重写规则可以使得你的静态页面路径和不使用静态缓存的url一样, 比如在不使用缓存的情况下, 你的url是 /node/get/ , 而使用缓存后, 假如缓存的HTML文件储存在 public/cached/node/get.html 下, 那么使用重写规则就可以使得用户继续使用 /node/get/ 这个url来访问它, 此时用户访问的就不再是PHP页面, 而是被重写到了 public/cached/node/get.html 这个静态页面. url依然保持一致.

    重写规则可以参考手册上的 Zend_Cache_Backend_Static , 这里抄录一份:

    AddType application/rss+xml .xml
    AddType application/atom+xml .xml
    
    RewriteEngine On
    
    RewriteCond %{REQUEST_URI} feed/rss$
    RewriteCond %{DOCUMENT_ROOT}/cached/%{REQUEST_URI}.xml -f
    RewriteRule .* cached/%{REQUEST_URI}.xml [L,T=application/rss+xml]
    
    RewriteCond %{REQUEST_URI} feed/atom$
    RewriteCond %{DOCUMENT_ROOT}/cached/%{REQUEST_URI}.xml -f
    RewriteRule .* cached/%{REQUEST_URI}.xml [L,T=application/atom+xml]
    
    RewriteCond %{DOCUMENT_ROOT}/cached/index.html -f
    RewriteRule ^/*$ cached/index.html [L]
    RewriteCond %{DOCUMENT_ROOT}/cached/%{REQUEST_URI}.(html|xml|json|opml|svg) -f
    RewriteRule .* cached/%{REQUEST_URI}.%1 [L]
    
    RewriteCond %{REQUEST_FILENAME} -s [OR]
    RewriteCond %{REQUEST_FILENAME} -l [OR]
    RewriteCond %{REQUEST_FILENAME} -d
    RewriteRule ^.*$ - [NC,L]
    
    RewriteRule ^.*$ index.php [NC,L]

    我测试出来是此重写规则在某些情况下是会失效的, 比如apache设置的virtualhost里会可能会出现问题(有些配置下), 原因是 %{REQUEST_URI} , 在有时候它会带前置的 / , 比如我请求 http://www.eriji.com/node , 按照重写规则, %{REQUEST_URI} 应该被解析为 node , 而有些设置下它是会被设置为 /node 的, 多一个 / , 使得重写失败, apache将不会重写到我们的缓存文件, 如果你确认的ZF生成了HTML文件到文件系统, 但是因为重定向的问题导致缓存没有被读取, 可以开启 mod_rewrite 的 rewriteLog , 查看具体重定向日志, 检查重写规则是否命中.

    3.4. 内部实现

    其实在了解了 ob_start(callback) 这个原理后, 我们自己都可以去实现HTML静态化, 但是在ZF里面, 唯一的问题是, 我们什么时候应该开启 ob_start , 而又到什么时候ZF才会把响应的内容(包括layout等)准备完毕, 也就是说什么时候使用 ob_end_lean ,特别是这个时机问题很重要, clean 早了可能缓存里面什么都没有, 也可能在使用了layout的情况下, 缓存里面只有action提供的view内容, 而没有 layout 部分.

    我们可以细致的研究下ZF的分发过程, 并且在其中观察 Zend_Controller_Action_Helper_Cache 是怎么来完成这个工作的, 从中可以了解到ZF的分发系统.

    首先我们从Controller_Action#init开始追踪, 因此我们在这一步里开始使用了cache helper.

    1. Controller_Action#init() , $this→_helper→cache(array(index), ..

    2. HelperBroker, 注册cache helper, Zend_Constroller_Action_Helper/Cache#direct

    3. Controller_Action#init(), 执行init()剩余部分

    4. Controller_Dispatcher(), 一系列分发

    5. Controller_Dispatcher_Standard#dispatch, 如果 disableOutputBuffering 没有指定则会调用 ob_start() 我们使用静态缓存的时候就必须关闭它.

    6. Controller_Action#dispatch(), action分发

    7. Controller_Action_Helper(), 分发到注册的action helper

    8. Constoller_Action_Helper_Cache()#preDispatch, 进入cache helper

    9. Zend_Cache_Frontend_Capture->start(), 调用 ob_start(array(this, "_flush"))

    10. Constoller_Front, 调用所有插件的postDispatch, $this→_plugins→postDispatch($this→_request)

    11. Zend_Layout_Controller_Plugin_Layout , layout插件对response→body进行处理, 目前的response→body中只有 action的view内容, 如果使用了layout, 这一步才会把layout的内容添加进来. 准确的说是把action view塞到layout里面去, 然后一起作为response→body.

    12. Zend_Cache_Frontend_Captrue#_flush($data) , 得到response→body, 将其作为data参数, 调用 Zend_Cache_Backend_Static#save($data, $id, $tag)

    13. Zend_Cache_Backend_Static#save, 调用 file_put_content 将响应内容输出到文件.

    14. 请求结束.

    其中关键的就是 912 , 都是 Zend_Cache_Frontend_Captrue 进行的操作, 使用的就是 ob_start(callback) 原理, 其中callback函数指定的是自己的 _flush 方法, 而在该方法里, 利用了 Zend_Cache_Backend_Static#save 来将缓存内容生成HTML文件.