再谈casperjs截图

遇到了什么问题

一直在使用 casperjs 来做网页截图,http://tool.lu/article

简单的使用是没有问题的,当要给墙外网址截图的时候,那么问题来了。

触发点:

  1. phantomjs 使用 proxy
  2. 要截图的网址是 https 的

现象:
被截取的网页会跳转到about:blank,导致截图空白

Eh, what the fuck?!

怎么解决的

最主要的是 --ssl-protocol=any --ignore-ssl-errors=true

基于之前那些个恶心的问题,然后就有了下面这么长的命令:

LC_CTYPE=en_US.UTF-8 PATH=/usr/local/phantomjs/bin:/usr/bin/usr/local/node/lib/node_modules/casperjs/bin/casperjs --proxy=127.0.0.1:7070 --proxy-type=socks5 --ssl-protocol=any --ignore-ssl-errors=true /data/jobs/webshot/webshot.js --url='https://url/you/want/to/capture/' --target='path/to/store/the/picture.png'

实时的 CPU 占用显示

预览

QQ20141108-1.png

流程

  1. golang 分析 vmstat 1 -n
  2. publish 到 redis
  3. subscribe redis 然后通过 SSE push 到 浏览器

代码

performance.go

go get gopkg.in/redis.v2
package main

import (
    "bufio"
    "fmt"
    "log"
    "io"
    "os/exec"
    "strings"
    "strconv"
    "gopkg.in/redis.v2"
)

var client *redis.Client

func tail(stream io.Reader) {
    scanner := bufio.NewScanner(stream)
    scanner.Scan() // 跳过header1
    scanner.Scan() // 跳过header2
    for scanner.Scan() {
        text := scanner.Text()
        segments := strings.Fields(text)
        if ide, err := strconv.ParseInt(segments[14], 10, 32); err == nil {
            used := 100 - ide
            log.Println(used)
            pub := client.Publish("performance", fmt.Sprintf("%d", used))
            if err := pub.Err(); err != nil {
                log.Println(err)
            }
        }
    }
    if err := scanner.Err(); err != nil {
        // ...
    }
}

func main () {
    client = redis.NewClient(&redis.Options{
        Network: "tcp",
        Addr: "127.0.0.1:6379",
    })
    outReader, outWriter := io.Pipe()
    cmd := exec.Command("vmstat", "1", "-n")
    cmd.Stdout = outWriter
    go tail(outReader)
    cmd.Run()
}

SSE 部分请自行实现 (提示:github上搜一下),使用nginx进行反向代理。

html部分

SmoothieChart
js/widget/performance/main.js

(function ($, SmoothieChart) {
    var chart = new SmoothieChart({
        minValue:0,
        maxValue:100,
        grid:{
            fillStyle:'#FFFFFF',
            strokeStyle:'#CCCCCC',
            sharpLines:true
        },
        labels: {
            fillStyle:'#333333',
        }
    }),
    canvas = document.getElementById('performance-widget'),
    series = new TimeSeries();

    chart.addTimeSeries(series, {lineWidth:2,strokeStyle:'#009A61',fillStyle:'rgba(0,154,97,.1)'});
    chart.streamTo(canvas, 500);

    if (!!window.EventSource) {
        var source = new EventSource('//your/sse/sever/and/path');
        source.addEventListener('performance', function (e) {
            series.append(+new Date(), +e.data);
        }, false);
    }

})(jQuery, SmoothieChart);

PS: Chrome的开发工具暂时无法看到浏览器返回的值,调试的话可以访问:chrome://view-http-cache/http(s)://your/sse/sever/and/path

使用 redis 做限流

背景

事情是这样来的,最近2天 tool.lu 的 uv 并没有大幅的增长,但是 pv 的涨幅却很大,造成服务器的 load 一度超过了 20,想必是被攻击,做过php-fpm的优化,收效甚微。故想到了限流

限流的使用场景

  1. API的调用次数限制
  2. 防止频繁刷新
  3. etc...

想法和实现

其实我是参考了下面这篇文章的实现,至于为什么要这么做,我的考虑跟他文章中提到的是一致的,可以查看原文

Rate limiting with Redis

原文中提供了大段的文字说明,于是我根据他的说明,做了一幅图,仅供参考:

design.jpg

这里需要说明的是,原文中使用的是redis中的hash,但是hash对其中的每个元素没有单独的失效时间,所以使用原文的方法是有bug的;

具体情况请看 issue

这里改用string类型来存储就可以啦!注意将 bucketSpanexpire 设置为同一个值

优化

使用string类型来存储,可以发现key的空间占用比较多,更耗内存了;我们可以压缩一下key来实现节省内存的目的。

实际应用

  1. tool.lu web限流 (php实现版本)
  2. coderunner sandbox限流 (go实现版本)

访问可视化

网站的统计

由于 tool.lu 的流量还不是很大,所以我把每次的访问记录都存到了MySQL(如果流量大,这么做是作死的节奏)

主要流程图

design1.jpg

design2.jpg

使用canal做异步处理,主要是因为

  1. ip => city的映射,可能要调用第三方接口比较耗时
  2. 网站代码处不需要写2份数据
  3. 装x

其中cannal分发的数据处理是用的java,本打算sse也用java的netty来实现了,惭愧,尝试未果后就放弃了,最后用golang实现的。

这样做不会太耗性能,而且每秒钟往客户端传输一次数据,但是由于 vps 的内存有限,java 又比较吃内存,所以上线之后就直接下线了。

youtube-dl无法下载的问题

使用youtube-dl下载youtube视频的时候出现下面的错误

ERROR: content too short

进过一番google之后,说是youtube服务器端那边的问题,可能会修复。最简单的解决办法就是更改一个清晰度差点的(默认下载选择的质量最好的那个),于是:

# 列出所有可用的
youtube-dl [url] -F
# format code extension resolution  note
# 139         m4a       audio only  DASH audio   51k , audio@ 48k (22050Hz), 19.03MiB (worst)
# 140         m4a       audio only  DASH audio  130k , audio@128k (44100Hz), 50.81MiB
# 141         m4a       audio only  DASH audio  258k , audio@256k (44100Hz), 102.01MiB
# 160         mp4       256x144     DASH video  122k , video only, 31.80MiB
# 133         mp4       426x240     DASH video  269k , video only, 50.52MiB
# 134         mp4       640x360     DASH video  281k , video only, 57.12MiB
# 135         mp4       854x480     DASH video  716k , video only, 134.81MiB
# 136         mp4       1280x720    DASH video  930k , video only, 104.83MiB
# 17          3gp       176x144
# 36          3gp       320x240
# 5           flv       400x240
# 43          webm      640x360
# 18          mp4       640x360
# 22          mp4       1280x720    (best)

# 选择一个质量稍差的

youtube-dl [url] -f18

从 php 内核挂载钩子解密源码

背景

大多数的php代码加密(不需要额外扩展就能运行的)原理上都是使用eval进行代码的执行,理论上,只要我们在php内核执行eval函数的时候,将其dump出来,就可以得到源代码。需要注意的是:

  1. 用户上传的代码是不可信的,因此需要一个沙盒
  2. 此法虽然方便,看似是一个万能解密的办法,但是 dump 数据的时候会有很多中间值,还是需要人工的做一个特征库,去识别过滤出需要的代码段

实现

在 php 扩展中, module init 的时候替换掉 zend_compile_string,主要代码如下

static zend_op_array *edump_compile_string(zval *source_string, char *filename TSRMLS_DC)
{
    int c, len;
    char *copy;
 
    if (Z_TYPE_P(source_string) != IS_STRING) {
        return orig_compile_string(source_string, filename TSRMLS_CC);
    }
 
    len  = Z_STRLEN_P(source_string);
    copy = estrndup(Z_STRVAL_P(source_string), len);
    if (len > strlen(copy)) {
        for (c=0; c<len; c++) if (copy[c] == 0) copy[c] == '?';
    }
 
    php_printf("----- [tool.lu start] -----\n");
    php_printf("%s\n", copy);
    php_printf("----- [tool.lu end] -----\n");
 
    yes = 1;

    return orig_compile_string(source_string, filename TSRMLS_CC);
}

PHP_MINIT_FUNCTION(edump)
{
    if (edump_hooked == 0) {
        edump_hooked = 1;
        orig_compile_string = zend_compile_string;
        zend_compile_string = edump_compile_string;
    }
    return SUCCESS;
}

使用docker作为沙盒

使用docker作为沙盒

背景

其实早就想做个在线代码运行的,但是 CentOS6 对 Docker 的支持不是很好,坑比较多。待 CentOS7 出来后思考了一段时间,最终还是决定做起来了。

怎么做

最初考虑的时候就是想着可以扩展性比较好的解决方案,建立一个socket sever可以把文件分发到不同的机器上,再后来便想着还是直接用rsync吧,然后...神马都没弄,就直接本地 mount 到 docker container 里面去了,做了个池子,最多只能开50个docker container

Dockerfile

FROM centos:latest

RUN yum install gcc gcc-c++ php golang -y

ADD entrypoint.sh entrypoint.sh
ADD run-code.sh run-code.sh

ENTRYPOINT ["/bin/bash", "entrypoint.sh"]

至于前端的东西,是用的CodeMirror,给他加了个命令和快捷键(mac 和 pc 区分)

preview

代码在线运行

Screenshot 2014-09-21 at 22.22.18.png

嵌入演示

nginx兼容%23

问题起源

在 tool.lu 上,将分享服务改为百度分享的时候,pc 上的分享链接都正常,但是微信二维码扫描之后就会出现下面的 url,%23也就是一个#

http://tool.lu/news/%2310006-weixin-1-6358-0629b82e8bd20c82f766611c23eca2f9

即使是在其提供的 api 中关闭#回流统计的功能,对二维码来说还是不起作用的。为对此url做兼容,修改 nginx 配置文件如下

解决方案

# hack for baidu share weixin
    rewrite ^(.*)\#(.*)$ $1#$2 redirect;
# end hack¬

使用casperjs截出优雅的图片

前言

  1. phantomjs中文问题
  2. phantomjs中文问题 [后续]

优化字体的显示

使用Chrome OS字体来代替serif, sans-serif, sans, monospace字体

/usr/share/fonts/default/truetype/croscorefonts
├── Arimo-BoldItalic.ttf
├── Arimo-Bold.ttf
├── Arimo-Italic.ttf
├── Arimo-Regular.ttf
├── Cousine-BoldItalic.ttf
├── Cousine-Bold.ttf
├── Cousine-Italic.ttf
├── Cousine-Regular.ttf
├── fonts.dir
├── fonts.scale
├── SymbolNeu.ttf
├── Tinos-BoldItalic.ttf
├── Tinos-Bold.ttf
├── Tinos-Italic.ttf
└── Tinos-Regular.ttf

0 directories, 15 files

~/.fonts.conf

<?xml version='1.0'?>
<!DOCTYPE fontconfig SYSTEM 'fonts.dtd'>
<fontconfig>

  <!-- Set preferred serif, sans serif, and monospace fonts. -->
  <alias>
    <family>serif</family>
    <prefer><family>Tinos</family></prefer>
  </alias>
  <alias>
    <family>sans-serif</family>
    <prefer><family>Arimo</family></prefer>
  </alias>
  <alias>
    <family>sans</family>
    <prefer><family>Arimo</family></prefer>
  </alias>
  <alias>
    <family>monospace</family>
    <prefer>
        <family>Meslo LG L DZ</family>
        <family>Cousine</family>
    </prefer>
  </alias>

  <!-- Aliases for commonly used MS fonts. -->
  <match>
    <test name="family"><string>Arial</string></test>
    <edit name="family" mode="assign" binding="strong">
      <string>Arimo</string>
    </edit>
  </match>
  <match>
    <test name="family"><string>Helvetica</string></test>
    <edit name="family" mode="assign" binding="strong">
      <string>Arimo</string>
    </edit>
  </match>
  <match>
    <test name="family"><string>Verdana</string></test>
    <edit name="family" mode="assign" binding="strong">
      <string>Arimo</string>
    </edit>
  </match>
  <match>
    <test name="family"><string>Tahoma</string></test>
    <edit name="family" mode="assign" binding="strong">
      <string>Arimo</string>
    </edit>
  </match>
  <match>
    <!-- Insert joke here -->
    <test name="family"><string>Comic Sans MS</string></test>
    <edit name="family" mode="assign" binding="strong">
      <string>Arimo</string>
    </edit>
  </match>
  <match>
    <test name="family"><string>Times New Roman</string></test>
    <edit name="family" mode="assign" binding="strong">
      <string>Tinos</string>
    </edit>
  </match>
  <match>
    <test name="family"><string>Times</string></test>
    <edit name="family" mode="assign" binding="strong">
      <string>Tinos</string>
    </edit>
  </match>
  <match>
    <test name="family"><string>Courier New</string></test>
    <edit name="family" mode="assign" binding="strong">
      <string>Cousine</string>
    </edit>
  </match>

  <match target="font" >
    <edit mode="assign" name="autohint" >
      <bool>true</bool>
    </edit>
  </match>
  <match target="font" >
    <edit mode="assign" name="rgba" >
      <const>none</const>
    </edit>
  </match>
  <match target="font" >
    <edit mode="assign" name="hinting" >
      <bool>false</bool>
    </edit>
  </match>
  <match target="font" >
    <edit mode="assign" name="hintstyle" >
      <const>hintnone</const>
    </edit>
  </match>
  <match target="font" >
    <edit mode="assign" name="antialias" >
      <bool>true</bool>
    </edit>
  </match>
</fontconfig>
fc-cache -fv
# 查看一下字体是否选择正确
fc-match monospace

js脚本

example.js

var fs = require('fs');

var casper = require('casper').create({
    stepTimeout: 3000
});

var url = casper.cli.get(0);
url = url || 'http://tool.lu/';

casper.start().viewport(1280, 800).thenOpen(url, function () {
    // this.captureSelector('snap.png', '.post');
    var filename = 'snap.png';
    this.capture(filename);
    this.echo(JSON.stringify({url: this.getCurrentUrl(), path : fs.absolute(filename)}));
});

casper.run();
casperjs example.js http://tool.lu/

效果图

snap.png

java中的线程池

为什么要使用线程池

  1. 重复利用已创建的线程降低线程创建和销毁造成的消耗
  2. 提高线程的可管理性,可进行统一的分配,调优和监控

线程池的处理流程

threadpool.jpg

ExecutorService

newCachedThreadPool();
newFixedThreadPool();
newScheduledThreadPool();
newSingleThreadExecutor();

ScheduledThreadPool使用优先级队列进行排序(距离下次调度间隔短的任务排在前面)
DelayedWorkQueue


package lu.tool.demo;

import java.util.concurrent.*;

/**
 * Created by xiaozi on 14-8-28.
 */
public class CachedThreadPoolDemo {

    public static void main(String[] args) {
        ExecutorService es = Executors.newCachedThreadPool();
        ThreadPoolExecutor tpe = (ThreadPoolExecutor) es;

//        tpe.setMaximumPoolSize(100);

        Future<?> future = null;
//        for (int i = 1; i < 8000; i++) {
        for (int i = 1; i < 100; i++) {
            future = tpe.submit(new TaskDemo());
        }

        System.out.println("largest pool size: " + tpe.getLargestPoolSize());
        System.out.println("task count: " + tpe.getTaskCount());

        if (future != null) {
            try {
                future.get();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }

//        tpe.shutdown();
    }
}
package lu.tool.demo;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * Created by xiaozi on 14-8-28.
 */
public class FixedThreadPoolDemo {

    public static void main(String[] args) {
        ExecutorService es = Executors.newFixedThreadPool(100);
        ThreadPoolExecutor tpe = (ThreadPoolExecutor) es;

        for (int i = 1; i < 8000; i++) {
            tpe.submit(new TaskDemo());
        }

        tpe.shutdown();
    }
}
package lu.tool.demo;

import java.util.concurrent.*;

/**
 * Created by xiaozi on 14-8-28.
 */
public class ScheduledThreadPoolDemo {

    public static void main(String[] args) {
        ScheduledExecutorService es = Executors.newScheduledThreadPool(100);

        for (int i = 1; i < 8000; i++) {
            es.schedule(new TaskDemo(), 3, TimeUnit.SECONDS);
        }

        // scheduleAtFixedRate
        // scheduleWithFixedDelay

        es.shutdown();
    }
}
package lu.tool.demo;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Created by xiaozi on 14-8-28.
 */
public class SingleThreadExecutorDemo {

    public static void main(String[] args) {
        ExecutorService es = Executors.newSingleThreadExecutor();

        for (int i = 1; i < 8000; i++) {
            es.submit(new TaskDemo());
        }

        es.shutdown();
    }
}

ThreadPoolExecutor

ThreadPoolExecutor(int corePoolSize,
                    int maximumPoolSize,
                    long keepAliveTime,
                    TimeUnit unit,
                    BlockingQueue<Runnable> workQueue,
                    RejectedExecutionHandler handler);
参数解释
corePoolSize线程池维护线程的最少数量
maximumPoolSize线程池维护线程的最大数量
keepAliveTime线程池维护线程所允许的空闲时间
unit线程池维护线程所允许的空闲时间的单位
workQueue线程池所使用的缓冲队列
handler线程池对拒绝任务的处理策略
package lu.tool.demo;


import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * Created by xiaozi on 14-8-29.
 */
public class ThreadPoolExecutorDemo {

    public static void main(String[] args) {
        ThreadPoolExecutor tpe = new ThreadPoolExecutor(3, 5, 60,
                                                        TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(10),
                                                        new ThreadPoolExecutor.CallerRunsPolicy());

        for (int i = 1; i < 8000; i++) {
            tpe.submit(new TaskDemo());
        }

        tpe.shutdown();
    }
}

阻塞队列

ArrayBlockingQueu   // 有界
LinkedBlockingQueue // 无界
SynchronousQueue
PriorityBlockingQueue

线程池的监控

beforeExecute(Thread t, Runnable r)
afterExecute(Runnable r, Throwable t)

executor.getTaskCount();
executor.getCompletedTaskCount();

executor.getLargestPoolSize();

executor.isShutdown();  
executor.isTerminated();

多少线程合适

  1. CPU密集型任务(ncpu + 1)
  2. I/O密集型任务(2 * ncpu)
  3. 任务的执行时间
  4. 任务的依赖性

阻塞队列的实现

线程池队列
ScheduledThreadPoolDelayedWorkQueueReentrantLock.newConditionavailable
FixedThreadPoolLinkedBlockingQueueReentrantLock.newConditionput, take
CachedThreadPoolSynchronousQueueReentrantLock
SingleThreadLinkedBlockingQueueReentrantLock.newConditionput, take

引用

  1. 聊聊并发(三)——JAVA线程池的分析和使用
  2. 线程池
  3. Java四种线程池的使用
  4. 多线程之线程池探索
  5. 深入浅出多线程(4)对CachedThreadPool OutOfMemoryError问题的一些想法
  6. ScheduledThreadPoolExecutor实现原理
  7. JAVA线程池ThreadPoolExecutor
  8. JAVA线程池学习以及队列拒绝策略

phantomjs中文问题 [后续]

之前写过一篇文章:phantomjs中文问题

里面的解决办法也是碰巧,如今将解决问题之所在。

# 列出所有已经安装的中文字体,如果还没有安装中文字体,可参考上文提到的文章。
fc-list :lang=zh
# 宋体,SimSun:style=Regular

# 看下字体是怎么走的
fc-match Arial -s
# SimSun.ttf: "SimSun" "Regular"
# n019003l.pfb: "Nimbus Sans L" "Regular"
# cursor.pfa: "Cursor" "Regular"
# d050000l.pfb: "Dingbats" "Regular"
# s050000l.pfb: "Standard Symbols L" "Regular"
# 哎呀,是对的呀,为什么phantomjs不认呢,(ÒωÓױ)

# 查看下本地语言设置
locale
# LANG=zh_CN.UTF-8
# LC_CTYPE=zh_CN.UTF-8
# LC_NUMERIC="zh_CN.UTF-8"
# LC_TIME="zh_CN.UTF-8"
# LC_COLLATE="zh_CN.UTF-8"
# LC_MONETARY="zh_CN.UTF-8"
# LC_MESSAGES="zh_CN.UTF-8"
# LC_PAPER="zh_CN.UTF-8"
# LC_NAME="zh_CN.UTF-8"
# LC_ADDRESS="zh_CN.UTF-8"
# LC_TELEPHONE="zh_CN.UTF-8"
# LC_MEASUREMENT="zh_CN.UTF-8"
# LC_IDENTIFICATION="zh_CN.UTF-8"
# LC_ALL=


# 嗯,据说 QT 在对“宋体,SimSun:style=Regular”处理的时候是有问题的
export LC_CTYPE=en_US.UTF-8
fc-list :lang=zh
# SimSun,宋体:style=Regular
# 换了个顺序,试试...,呵呵,phantomjs中文的问题解决了 - - |||

因为不需要全局修改LC_CTYPE,所以在命令前面加一下就好了。为了方便写个alias

alias casperjs='LC_CTYPE=en_US.UTF-8 casperjs'

悬疑推理分类

悬疑推理

犯罪

1.沉默的羔羊系列

  赤龙
  汉尼拔
  沉默的羔羊

2.记忆碎片

3.十二宫杀手

4.足迹 Sleuth

5.王牌对王牌 The Negotiator

6.东方快车谋杀案 Murder on the Orient Express (1974)

7.大卫·戈尔的一生 The Life of David Gale

8.不道德的审判 Death and the Maiden

惊悚/恐怖

1.恐怖游轮

2.时空罪恶

3.禁闭岛

4.穆赫兰道

5.万能钥匙

6.心慌方

  异次元杀阵
  异次元杀阵3:前传
  异次元杀阵2:超级立方体

7.第六感 The Sixth Sense

8.十二猴子

9.蝴蝶效应 The Butterfly Effect (2004)

剧情

1.飞跃疯人院

2.搏击俱乐部

3.永无止境

4.低俗小说

5.猜火车

6.魔术师 The Illusionist

*7.盗墓者的忏悔 I Sell The Dead

8.时空三部曲

  天堂电影院
  海上钢琴师
  西西里的美丽传说

9.放牛班的春天 Les choristes

10.死亡诗社 Dead Poets Society

11.闻香识女人 Scent of a Woman

12.当幸福来敲门 The Pursuit of Happyness

13.燃情岁月 Legends of the Fall

14.国王的演讲 The King's Speech

15.贫民窟的百万富翁 Slumdog Millionaire

16.触不可及 Intouchables

17.心灵捕手 Good Will Hunting

18.七磅 Seven Pounds

19.美丽人生 La vita è bella

20.小鞋子 بچههای آسمان

21.偷自行车的人 Ladri di biciclette

22.蝴蝶 Le Papillon

23.中央车站 Central do Brasil

24.大鱼 Big Fish

25.勇敢的心 Braveheart

26.角斗士 Gladiator

27.美国丽人 American Beauty

28.十二怒汉 12 Angry Men (1957) (1997)(2007)

29.她比烟花寂寞 Hilary and Jackie

30.走出非洲 Out of Africa

31.玫瑰人生 La Môme

32.窃听风暴 Das Leben der Anderen

33.水果硬糖

34.拯救大兵瑞恩

35.八月迷情 August Rush

36.超脱 Detachment

37.蝙蝠侠系列

   蝙蝠侠:侠影之谜 Batman Begins (2005)
   蝙蝠侠:黑暗骑士 The Dark Knight (2008)
   蝙蝠侠:黑暗骑士崛起 The Dark Knight Rises (2012)

38.阳光小美女 Little Miss Sunshine

39.天才瑞普利 The Talented Mr. Ripley

40.碟中谍系列

   碟中谍 Mission: Impossible (1996)
   碟中谍2 Mission: Impossible II (2000)
   碟中谍3 Mission: Impossible III (2006)
   碟中谍4 Mission: Impossible - Ghost Protocol (2011)

41.谍影重重系列

   谍影重重 The Bourne Identity (2002)
   谍影重重2 The Bourne Supremacy (2004)
   谍影重重3 The Bourne Ultimatum (2007)
   谍影重重4 The Bourne Legacy (2012)

42.洛奇系列

   洛奇 Rocky (1976)
   洛奇2 Rocky II (1979)
   洛奇3 Rocky III (1982)
   洛奇4 Rocky IV (1985)
   洛奇5 Rocky V (1990)
   洛奇6:永远的拳王 Rocky Balboa (2006)

43.第一滴血系列

   第一滴血 First Blood (1982)
   第一滴血2 Rambo: First Blood Part II (1985)
   第一滴血3 Rambo III (1988)
   第一滴血4 Rambo (2008)

44.行动目标希特勒 Valkyrie

45.希望与荣耀 Hope and Glory

46.音乐永不停止 The Music Never Stopped

47.勇士 Warrior

48.斯图尔特:倒带人生 Stuart: A Life Backwards

49.美国往事 Once Upon a Time in America

50.逃离德黑兰 Argo

51.德黑兰43年 Тегеран-43

52.锅匠,裁缝,士兵,间谍 Tinker Tailor Soldier Spy

53.无耻混蛋 Inglourious Basterds

54.追风筝的人 The Kite Runner

55.两杆大烟枪 Lock, Stock and Two Smoking Barrels

56.偷拐抢骗 Snatch

57冰上轻驰 Cool Runnings

58.一次别离 جدایی نادر از سیمین

59.狩猎 Jagten

60.调音师 L'accordeur

61.天生杀人狂 Natural Born Killers

62.上帝之城 Cidade de Deus

63.登堂入室 Dans la maison

64.我是山姆 I Am Sam (2001)

65.狗镇 Dogville (2003)

66.克洛伊 Chloe

67.水中刀 Nóz w wodzie (1962)

68.邮差 Il postino (1994)

69.出租车司机 Taxi Driver (1976)

70.对她说 Hable con ella (2002)

71.布朗克斯的故事 A Bronx Tale (1993)

72.K星异客 K-PAX (2001)

73.这个男人来自地球 The Man from Earth (2007)

74.碧海蓝天 Le grand bleu (1988)

75.海盗电台 The Boat That Rocked

76.危情三日 The Next Three Days

77.这个杀手不太冷 Léon

78.巴黎,我爱你 Paris, je t'aime

79.疤面煞星 Scarface (1983)

80.荒岛余生 Cast Away

81.谜中谜 Charade (1963)

82.金蝉脱壳

83.罗拉快跑 Lola rennt (1998)

84.雌雄大盗 Bonnie and Clyde

85.雾中风景 Τοπίο στην ομίχλη

86.内布拉斯加 Nebraska

87.弱点 The Blind Side

88.感谢你抽烟 Thank You for Smoking

89.壮志凌云 Top Gun

90.通天塔 Babel

91.老无所依 No Country for Old Men

92.大地雄心 Far and Away

93.大河恋 A River Runs Through It

94.遗愿清单 The Bucket List

95.不可饶恕 Unforgiven

96.百万美元宝贝 Million Dollar Baby

97.撞车 Crash

98.钢琴家 The Pianist

99.布达佩斯大饭店 The Grand Budapest Hotel

科幻/奇幻

1.永无止境

2.时间规划局 In Time

3.楚门的世界

4.心灵传输者 Jumper

5.我是传奇 I Am Legend

6.香水 Perfume: The Story of a Murderer

7.人工智能 Artificial Intelligence: AI

8.铁甲钢拳 Real Steel

9.黑天鹅 Black Swan

10.潘神的迷宫 El laberinto del fauno

11.V字仇杀队 V for Vendetta

12.绿里奇迹 The Green Mile

13.夜访吸血鬼 Interview with the Vampire: The Vampire Chronicles

14.云图 Cloud Atla

15.午夜巴黎 Midnight in Paris (2011)

16.少年派的奇幻漂流 Life of Pi

17.白日梦想家 The Secret Life of Walter Mitty

18.机器管家 Bicentennial Man

19.土拨鼠之日 Groundhog Day

真实故事改编/传记/小说改编

1.死亡实验 Das Experiment

2.美丽心灵 A Beautiful Mind

3.穿条纹睡衣的男孩 The Boy in the Striped Pajamas

4.日瓦戈医生 Doctor Zhivago (1965)

5.卢旺达饭店 Hotel Rwanda

6.布拉格之恋 The Unbearable Lightness of Bein

7.基督山伯爵 The Count of Monte Cristo

8.莎翁情史 Shakespeare in Love

9.摩托日记 Diarios de motocicleta

10.荆棘鸟 The Thorn Birds

11.教父系列 The Godfather

   教父 The Godfather (1972)
   教父2 The Godfather: Part Ⅱ (1974)
   教父3 The Godfather: Part III (1990)

12.洛城机密 L.A. Confidential

13.莫扎特传 Amadeus (1984)

14.刺杀肯尼迪 JFK (1991)

15.浪潮 Die Welle (2008)

16.叫我第一名 Front of the Class

17.寻找小糖人 Searching for Sugar Man

18.兰迪·波许教授的最后一课 Randy Pausch's Last Lecture

19.十月的天空 October Sky

20.情人 L'amant (1992)

21.弗里达 Frida (2002)

22.情迷六月花 Henry & June

23.罗丹的情人 Camille Claudel (1988)

24.阿黛尔·雨果的故事 L'histoire d'Adèle H. (1975)

25.倾国之恋 W.E. (2011)

26.永远的车神 Senna (2010)

27.极速风流 Rush (2013)

28.圣安娜奇迹 Miracle at St. Anna (2008)

29.荒野生存 Into the Wild

30.菲利普船长 Captain Phillips

种族/社会问题

1.紫色 The Color Purple

2.光荣之路 Glory Road

3.为奴十二载 12 Years a Slave

4.美国X档案 American History X

5.达拉斯买家俱乐部 Dallas Buyers Club (2013)

6.远离天堂 Far from Heaven

7.费城故事 Philadelphia (1993)

8.勇者无惧 Amistad

一些php扩展的资料整理

Thread-Safe 宏

TSRM

Thread-Safe Resource Manager
线程安全资源管理

ZTS

Zend Thread Safety
Zend 线程安全

tsrm_ls

TSRM local storage
线程安全资源管理 本地存储

TSRMLS_??

TSRMLS_C tsrm_ls
TSRMLS_D void ***tsrm_ls
TSRMLS_CC , tsrm_ls
TSRMLS_DC , void ***tsrm_ls
CC - call with comma
     前置逗号的调用
C  - call
     调用
DC - declaration with comma
     前置逗号的声明
D  - declaration
     声明

zend_parse_parameters

类型符号

类型字符php参数类型c类型
llonglong
ddoubledouble
sstringchar* / int
bbooleanzend_bool
rresourcezval*
aarrayzval*
zzvalzval*
Zzvalzval**
ffunctionfunction
o/Oclasszval, zend_class_entry

控制字符

控制字符作用
|它之前的参数都是必须的,之后的都是非必须的,也就是有默认值的。
!如果接收了一个PHP语言里的null变量,则直接把其转成C语言里的NULL,而不是封装成IS_NULL类型的zval。
/如果传递过来的变量与别的变量共用一个zval,而且不是引用,则进行强制分离,新的zval的is_ref__gc==0, and refcount__gc==1.

返回值

返回函数
RETURN_RESOURCE(resource)
RETURN_BOOL(bool)
RETURN_NULL()
RETURN_LONG(long)
RETURN_DOUBLE(double)
RETURN_STRING(string, duplicate)
RETURN_STRINGL(string, length, duplicate)
RETURN_EMPTY_STRING()
RETURN_FALSE()
RETURN_TRUE()

helpers

helperexpanded解释
ZEND_FE_END(){NULL, NULL, NULL}用于zend_function_entry的最后一行
ZEND_STRL("str")"str", strlen("str")用于同时需要字符串和其长度的函数中